VirtualBox

Changeset 84819 in vbox for trunk/src/VBox/Devices/VirtIO


Ignore:
Timestamp:
Jun 12, 2020 8:00:27 PM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
138625
Message:

Virtio/VirtioCore.cpp, Network/DevVirtioNet_1_0.cpp, Storage/DevVirtioSCSI.cpp: Renamed Virtio_1_0.cpp/h to VirtioCore.cpp/h to be consistent with bird's extraction of the common Virtio code to VIRTIOCORE. Further improved the API function names and comments, and changed key variables to simplify things and more clearly reflect their relationship to VirtIO architecture. For example PVIRTIO_DESC_CHAIN_T pDescChain becomes PVIRTQBUF pVirtqBuf and added comments above the VIRTQBUF typedef to explain what's going on. Moved all the API function descriptions into the header file.

Location:
trunk/src/VBox/Devices/VirtIO
Files:
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp

    r84818 r84819  
    11/* $Id$ */
     2
    23/** @file
    3  * Virtio_1_0 - Virtio Common (PCI, feature & config mgt, queue mgt & proxy, notification mgt)
     4 * VirtioCore - Virtio Core (PCI, feature & config mgt, queue mgt & proxy, notification mgt)
    45 */
    56
     
    3536#include <VBox/AssertGuest.h>
    3637#include <VBox/vmm/pdmdev.h>
    37 #include "Virtio_1_0.h"
     38#include "VirtioCore.h"
    3839
    3940
     
    4243*********************************************************************************************************************************/
    4344#define INSTANCE(a_pVirtio)                 ((a_pVirtio)->szInstance)
    44 #define VIRTQNAME(a_pVirtio, a_idxVirtq)    ((a_pVirtio)->aVirtqState[(a_idxVirtq)].szVirtqName)
     45#define VIRTQNAME(a_pVirtio, a_uVirtqNbr)    ((a_pVirtio)->aVirtqState[(a_uVirtqNbr)].szVirtqName)
    4546#define IS_DRIVER_OK(a_pVirtio)             ((a_pVirtio)->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    4647#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtqState) \
     
    135136/* Internal Functions */
    136137
    137 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);
     138static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
    138139static int  virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec);
    139140
     
    145146 */
    146147#ifdef IN_RING3
    147 DECLINLINE(void) virtioReadDesc(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
     148DECLINLINE(void) virtioReadDesc(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
    148149                                uint32_t idxDesc, PVIRTQ_DESC_T pDesc)
    149150{
    150151    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    151     uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[idxVirtq], 1); /* Make sure to avoid div-by-zero. */
     152    uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[uVirtqNbr], 1); /* Make sure to avoid div-by-zero. */
    152153    PDMDevHlpPCIPhysRead(pDevIns,
    153                       pVirtio->aGCPhysVirtqDesc[idxVirtq] + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
     154                      pVirtio->aGCPhysVirtqDesc[uVirtqNbr] + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
    154155                      pDesc, sizeof(VIRTQ_DESC_T));
    155156}
     
    160161 */
    161162#ifdef IN_RING3
    162 DECLINLINE(uint16_t) virtioReadAvailDescIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint32_t availIdx)
     163DECLINLINE(uint16_t) virtioReadAvailDescIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint32_t availIdx)
    163164{
    164165    uint16_t uDescIdx;
    165166    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    166     uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[idxVirtq], 1); /* Make sure to avoid div-by-zero. */
     167    uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[uVirtqNbr], 1); /* Make sure to avoid div-by-zero. */
    167168    PDMDevHlpPCIPhysRead(pDevIns,
    168                         pVirtio->aGCPhysVirtqAvail[idxVirtq]
     169                        pVirtio->aGCPhysVirtqAvail[uVirtqNbr]
    169170                      + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % cVirtqItems]),
    170171                      &uDescIdx, sizeof(uDescIdx));
     
    172173}
    173174
    174 DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
     175DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
    175176{
    176177    uint16_t uUsedEventIdx;
     
    178179    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    179180    PDMDevHlpPCIPhysRead(pDevIns,
    180                       pVirtio->aGCPhysVirtqAvail[idxVirtq] + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uVirtqSize[idxVirtq]]),
     181                      pVirtio->aGCPhysVirtqAvail[uVirtqNbr] + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uVirtqSize[uVirtqNbr]]),
    181182                      &uUsedEventIdx, sizeof(uUsedEventIdx));
    182183    return uUsedEventIdx;
     
    184185#endif
    185186
    186 DECLINLINE(uint16_t) virtioReadAvailRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
     187DECLINLINE(uint16_t) virtioReadAvailRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
    187188{
    188189    uint16_t uIdx = 0;
    189190    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    190191    PDMDevHlpPCIPhysRead(pDevIns,
    191                       pVirtio->aGCPhysVirtqAvail[idxVirtq] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
     192                      pVirtio->aGCPhysVirtqAvail[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
    192193                      &uIdx, sizeof(uIdx));
    193194    return uIdx;
    194195}
    195196
    196 DECLINLINE(uint16_t) virtioReadAvailRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
     197DECLINLINE(uint16_t) virtioReadAvailRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
    197198{
    198199    uint16_t fFlags = 0;
    199200    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    200201    PDMDevHlpPCIPhysRead(pDevIns,
    201                       pVirtio->aGCPhysVirtqAvail[idxVirtq] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
     202                      pVirtio->aGCPhysVirtqAvail[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
    202203                      &fFlags, sizeof(fFlags));
    203204    return fFlags;
     
    211212
    212213#ifdef IN_RING3
    213 DECLINLINE(void) virtioWriteUsedElem(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
     214DECLINLINE(void) virtioWriteUsedElem(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
    214215                                     uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen)
    215216{
    216217    VIRTQ_USED_ELEM_T elem = { uDescIdx,  uLen };
    217218    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    218     uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[idxVirtq], 1); /* Make sure to avoid div-by-zero. */
     219    uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[uVirtqNbr], 1); /* Make sure to avoid div-by-zero. */
    219220    PDMDevHlpPCIPhysWrite(pDevIns,
    220                           pVirtio->aGCPhysVirtqUsed[idxVirtq] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cVirtqItems]),
     221                          pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cVirtqItems]),
    221222                          &elem, sizeof(elem));
    222223}
    223224
    224 DECLINLINE(void) virtioWriteUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint16_t fFlags)
     225DECLINLINE(void) virtioWriteUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint16_t fFlags)
    225226{
    226227    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    227228    RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
    228229    PDMDevHlpPCIPhysWrite(pDevIns,
    229                           pVirtio->aGCPhysVirtqUsed[idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
     230                          pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
    230231                          &fFlags, sizeof(fFlags));
    231232}
    232233#endif
    233234
    234 DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint16_t uIdx)
     235DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint16_t uIdx)
    235236{
    236237    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    237238    PDMDevHlpPCIPhysWrite(pDevIns,
    238                           pVirtio->aGCPhysVirtqUsed[idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
     239                          pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    239240                          &uIdx, sizeof(uIdx));
    240241}
     
    243244#ifdef IN_RING3
    244245
    245 DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
     246DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
    246247{
    247248    uint16_t uIdx = 0;
    248249    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    249250    PDMDevHlpPCIPhysRead(pDevIns,
    250                       pVirtio->aGCPhysVirtqUsed[idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
     251                      pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    251252                      &uIdx, sizeof(uIdx));
    252253    return uIdx;
    253254}
    254255
    255 DECLINLINE(uint16_t) virtioReadUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
     256DECLINLINE(uint16_t) virtioReadUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
    256257{
    257258    uint16_t fFlags = 0;
    258259    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    259260    PDMDevHlpPCIPhysRead(pDevIns,
    260                       pVirtio->aGCPhysVirtqUsed[idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
     261                      pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
    261262                      &fFlags, sizeof(fFlags));
    262263    return fFlags;
    263264}
    264265
    265 DECLINLINE(void) virtioWriteUsedAvailEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint32_t uAvailEventIdx)
     266DECLINLINE(void) virtioWriteUsedAvailEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint32_t uAvailEventIdx)
    266267{
    267268    /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
    268269    AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    269270    PDMDevHlpPCIPhysWrite(pDevIns,
    270                           pVirtio->aGCPhysVirtqUsed[idxVirtq] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtio->uVirtqSize[idxVirtq]]),
     271                          pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtio->uVirtqSize[uVirtqNbr]]),
    271272                          &uAvailEventIdx, sizeof(uAvailEventIdx));
    272273}
     
    277278DECLINLINE(uint16_t) virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQSTATE pVirtqState)
    278279{
    279     uint16_t uIdx    = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtqState->idxVirtq);
     280    uint16_t uIdx    = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtqState->uVirtqNbr);
    280281    uint16_t uShadow = pVirtqState->uAvailIdxShadow;
    281282
     
    287288
    288289    LogFunc(("%s has %u %s (idx=%u shadow=%u)\n",
    289         VIRTQNAME(pVirtio, pVirtqState->idxVirtq), uDelta, uDelta == 1 ? "entry" : "entries",
     290        VIRTQNAME(pVirtio, pVirtqState->uVirtqNbr), uDelta, uDelta == 1 ? "entry" : "entries",
    290291        uIdx, uShadow));
    291292
     
    297298 * @param   pDevIns     The device instance.
    298299 * @param   pVirtio     Pointer to the shared virtio state.
    299  * @param   idxVirtq    Virtq number
     300 * @param   uVirtqNbr    Virtq number
    300301 *
    301302 * @returns how many entries have been added to ring as a delta of the consumer's
    302303 *          avail index and the queue's guest-side current avail index.
    303304 */
    304 uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    305 {
    306     if (!IS_DRIVER_OK(pVirtio) || !pVirtio->uVirtqEnable[idxVirtq])
     305uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     306{
     307    if (!IS_DRIVER_OK(pVirtio) || !pVirtio->uVirtqEnable[uVirtqNbr])
    307308    {
    308309        LogRelFunc(("Driver not ready or queue not enabled\n"));
    309310        return 0;
    310311    }
    311     return virtioCoreVirtqAvailCount(pDevIns, pVirtio, &pVirtio->aVirtqState[idxVirtq]);
     312    return virtioCoreVirtqAvailCount(pDevIns, pVirtio, &pVirtio->aVirtqState[uVirtqNbr]);
    312313}
    313314
     
    435436
    436437#ifdef IN_RING3
     438
     439/** API Function: See header file*/
    437440void virtioCorePrintFeatures(VIRTIOCORE *pVirtio, PCDBGFINFOHLP pHlp)
    438441{
     
    478481
    479482#ifdef LOG_ENABLED
    480 /**
    481  * Debug assist for consumer device code.
    482  * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to
    483  * control enabling of logging efficiently.
    484  *
    485  * @param   pv          pointer to buffer to dump contents of
    486  * @param   cb          count of characters to dump from buffer
    487  * @param   uBase       base address of per-row address prefixing of hex output
    488  * @param   pszTitle    Optional title. If present displays title that lists
    489  *                      provided text with value of cb to indicate size next to it.
    490  */
     483
     484/** API Function: See header file */
    491485void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle)
    492486{
     
    527521}
    528522
    529 /**
    530  * Debug assist for consumer device code.
    531  * Do a hex dump of memory in guest physical context
    532  *
    533  * @param   GCPhys      pointer to buffer to dump contents of
    534  * @param   cb          count of characters to dump from buffer
    535  * @param   uBase       base address of per-row address prefixing of hex output
    536  * @param   pszTitle    Optional title. If present displays title that lists
    537  *                      provided text with value of cb to indicate size next to it.
    538  */
     523/* API FUnction: See header file */
    539524void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle)
    540525{
     
    579564#endif /* LOG_ENABLED */
    580565
    581 /**
    582  * Log memory-mapped I/O input or output value.
    583  *
    584  * This is designed to be invoked by macros that can make contextual assumptions
    585  * (e.g. implicitly derive MACRO parameters from the invoking function). It is exposed
    586  * for the VirtIO client doing the device-specific implementation in order to log in a
    587  * similar fashion accesses to the device-specific MMIO configuration structure. Macros
    588  * that leverage this function are found in virtioCommonCfgAccessed() and can be
    589  * used as an example of how to use this effectively for the device-specific
    590  * code.
    591  *
    592  * @param   pszFunc     To avoid displaying this function's name via __FUNCTION__ or LogFunc()
    593  * @param   pszMember   Name of struct member
    594  * @param   pv          pointer to value
    595  * @param   cb          size of value
    596  * @param   uOffset     offset into member where value starts
    597  * @param   fWrite      True if write I/O
    598  * @param   fHasIndex   True if the member is indexed
    599  * @param   idx         The index if fHasIndex
    600  */
     566/** API function: See header file */
    601567void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
    602568                                const void *pv, uint32_t cb, uint32_t uOffset, int fWrite,
     
    673639#ifdef IN_RING3
    674640
    675 void virtioCoreR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    676 {
    677     RT_NOREF(pDevIns);
    678     bool fNone     = pszArgs && *pszArgs == '\0';
    679     bool fAll      = pszArgs && (*pszArgs == 'a' || *pszArgs == 'A'); /* "all"      */
    680     bool fBasic    = pszArgs && (*pszArgs == 'b' || *pszArgs == 'B'); /* "basic"    */
    681     bool fState    = pszArgs && (*pszArgs == 's' || *pszArgs == 'S'); /* "state"    */
    682     bool fPointers = pszArgs && (*pszArgs == 'p' || *pszArgs == 'P'); /* "pointers" */
    683     bool fVirtqs   = pszArgs && (*pszArgs == 'q' || *pszArgs == 'Q'); /* "queues    */
    684     RT_NOREF6(fNone, fAll, fBasic, fState, fPointers, fVirtqs);
    685     pHlp->pfnPrintf(pHlp, "");
    686 
    687 }
    688 
    689 void virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int idxVirtq)
     641/** API Fuunction: See header file */
     642void virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int uVirtqNbr)
    690643{
    691644    RT_NOREF(pszArgs);
    692645    PVIRTIOCORE pVirtio = PDMDEVINS_2_DATA(pDevIns, PVIRTIOCORE);
    693     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
    694 
    695 //    bool fDump      = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)"       */
    696 
    697     uint16_t uAvailIdx       = virtioReadAvailRingIdx(pDevIns, pVirtio, idxVirtq);
     646    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
     647
     648    /** @todo add ability to dump physical contents of any descriptor (using existing VirtIO core API function) */
     649//    bool fDump      = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)"
     650
     651    uint16_t uAvailIdx       = virtioReadAvailRingIdx(pDevIns, pVirtio, uVirtqNbr);
    698652    uint16_t uAvailIdxShadow = pVirtqState->uAvailIdxShadow;
    699653
    700     uint16_t uUsedIdx        = virtioReadUsedRingIdx(pDevIns, pVirtio, idxVirtq);
     654    uint16_t uUsedIdx        = virtioReadUsedRingIdx(pDevIns, pVirtio, uVirtqNbr);
    701655    uint16_t uUsedIdxShadow  = pVirtqState->uUsedIdxShadow;
    702656
    703     PVIRTIO_DESC_CHAIN_T pDescChain = NULL;
     657    PVIRTQBUF pVirtqBuf = NULL;
    704658
    705659    bool fEmpty = IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtqState);
    706660
    707     LogFunc(("%s, empty = %s\n", VIRTQNAME(pVirtio, idxVirtq), fEmpty ? "true" : "false"));
     661    LogFunc(("%s, empty = %s\n", VIRTQNAME(pVirtio, uVirtqNbr), fEmpty ? "true" : "false"));
    708662
    709663    int cSendSegs = 0, cReturnSegs = 0;
    710664    if (!fEmpty)
    711665    {
    712         virtioCoreR3VirtqPeek(pDevIns,  pVirtio, idxVirtq, &pDescChain);
    713         cSendSegs   = pDescChain->pSgPhysSend ? pDescChain->pSgPhysSend->cSegs : 0;
    714         cReturnSegs = pDescChain->pSgPhysReturn ? pDescChain->pSgPhysReturn->cSegs : 0;
    715     }
    716 
    717     bool fAvailNoInterrupt   = virtioReadAvailRingFlags(pDevIns, pVirtio, idxVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT;
    718     bool fUsedNoNotify       = virtioReadUsedRingFlags(pDevIns, pVirtio, idxVirtq) & VIRTQ_USED_F_NO_NOTIFY;
    719 
    720 
    721     pHlp->pfnPrintf(pHlp, "       queue enabled: ........... %s\n", pVirtio->uVirtqEnable[idxVirtq] ? "true" : "false");
    722     pHlp->pfnPrintf(pHlp, "       size: .................... %d\n", pVirtio->uVirtqSize[idxVirtq]);
    723     pHlp->pfnPrintf(pHlp, "       notify offset: ........... %d\n", pVirtio->uVirtqNotifyOff[idxVirtq]);
     666        virtioCoreR3VirtqBufPeek(pDevIns,  pVirtio, uVirtqNbr, &pVirtqBuf);
     667        cSendSegs   = pVirtqBuf->pSgPhysSend ? pVirtqBuf->pSgPhysSend->cSegs : 0;
     668        cReturnSegs = pVirtqBuf->pSgPhysReturn ? pVirtqBuf->pSgPhysReturn->cSegs : 0;
     669    }
     670
     671    bool fAvailNoInterrupt   = virtioReadAvailRingFlags(pDevIns, pVirtio, uVirtqNbr) & VIRTQ_AVAIL_F_NO_INTERRUPT;
     672    bool fUsedNoNotify       = virtioReadUsedRingFlags(pDevIns, pVirtio, uVirtqNbr) & VIRTQ_USED_F_NO_NOTIFY;
     673
     674
     675    pHlp->pfnPrintf(pHlp, "       queue enabled: ........... %s\n", pVirtio->uVirtqEnable[uVirtqNbr] ? "true" : "false");
     676    pHlp->pfnPrintf(pHlp, "       size: .................... %d\n", pVirtio->uVirtqSize[uVirtqNbr]);
     677    pHlp->pfnPrintf(pHlp, "       notify offset: ........... %d\n", pVirtio->uVirtqNotifyOff[uVirtqNbr]);
    724678    if (pVirtio->fMsiSupport)
    725         pHlp->pfnPrintf(pHlp, "       MSIX vector: ....... %4.4x\n", pVirtio->uVirtqMsixVector[idxVirtq]);
     679        pHlp->pfnPrintf(pHlp, "       MSIX vector: ....... %4.4x\n", pVirtio->uVirtqMsixVector[uVirtqNbr]);
    726680    pHlp->pfnPrintf(pHlp, "\n");
    727681    pHlp->pfnPrintf(pHlp, "       avail ring (%d entries):\n", uAvailIdx - uAvailIdxShadow);
     
    740694        pHlp->pfnPrintf(pHlp, "          head idx: ............. %d\n", uUsedIdx);
    741695        pHlp->pfnPrintf(pHlp, "          segs: ................. %d\n", cSendSegs + cReturnSegs);
    742         pHlp->pfnPrintf(pHlp, "          refCnt ................ %d\n", pDescChain->cRefs);
     696        pHlp->pfnPrintf(pHlp, "          refCnt ................ %d\n", pVirtqBuf->cRefs);
    743697        pHlp->pfnPrintf(pHlp, "\n");
    744         pHlp->pfnPrintf(pHlp, "          host-to-guest (%d bytes):\n",      pDescChain->cbPhysSend);
     698        pHlp->pfnPrintf(pHlp, "          host-to-guest (%d bytes):\n",      pVirtqBuf->cbPhysSend);
    745699        pHlp->pfnPrintf(pHlp,     "             segs: .............. %d\n", cSendSegs);
    746700        if (cSendSegs)
    747701        {
    748             pHlp->pfnPrintf(pHlp, "             index: ............. %d\n", pDescChain->pSgPhysSend->idxSeg);
    749             pHlp->pfnPrintf(pHlp, "             unsent ............. %d\n", pDescChain->pSgPhysSend->cbSegLeft);
     702            pHlp->pfnPrintf(pHlp, "             index: ............. %d\n", pVirtqBuf->pSgPhysSend->idxSeg);
     703            pHlp->pfnPrintf(pHlp, "             unsent ............. %d\n", pVirtqBuf->pSgPhysSend->cbSegLeft);
    750704        }
    751705        pHlp->pfnPrintf(pHlp, "\n");
    752         pHlp->pfnPrintf(pHlp,     "          guest-to-host (%d bytes)\n",   pDescChain->cbPhysReturn);
     706        pHlp->pfnPrintf(pHlp,     "          guest-to-host (%d bytes)\n",   pVirtqBuf->cbPhysReturn);
    753707        pHlp->pfnPrintf(pHlp,     "             segs: .............. %d\n", cReturnSegs);
    754708        if (cReturnSegs)
    755709        {
    756             pHlp->pfnPrintf(pHlp, "             index: ............. %d\n", pDescChain->pSgPhysReturn->idxSeg);
    757             pHlp->pfnPrintf(pHlp, "             unsent ............. %d\n", pDescChain->pSgPhysReturn->cbSegLeft);
     710            pHlp->pfnPrintf(pHlp, "             index: ............. %d\n", pVirtqBuf->pSgPhysReturn->idxSeg);
     711            pHlp->pfnPrintf(pHlp, "             unsent ............. %d\n", pVirtqBuf->pSgPhysReturn->cbSegLeft);
    758712        }
    759713    } else
     
    763717}
    764718
    765 /**
    766  * Allocate client context for client to work with VirtIO-#provided with queue
    767  *
    768  * @param   pVirtio     Pointer to the shared virtio state.
    769  * @param   idxVirtq    Virtq number
    770  * @param   pcszName    Name to give queue
    771  *
    772  * @returns VBox status code.
    773  */
    774 int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t idxVirtq, const char *pcszName)
     719int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, const char *pcszName)
    775720{
    776721    LogFunc(("%s\n", pcszName));
    777     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
    778     pVirtqState->idxVirtq = idxVirtq;
     722    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
     723    pVirtqState->uVirtqNbr = uVirtqNbr;
    779724    pVirtqState->uAvailIdxShadow = 0;
    780725    pVirtqState->uUsedIdxShadow  = 0;
     
    788733#ifdef IN_RING3
    789734
    790 int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
    791                              uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain)
    792 {
    793     AssertReturn(ppDescChain, VERR_INVALID_POINTER);
    794     *ppDescChain = NULL;
    795 
    796     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    797 
    798     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
    799 
    800     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[idxVirtq],
     735/** API Function: See header file */
     736int virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
     737                             uint16_t uHeadIdx, PPVIRTQBUF ppVirtqBuf)
     738{
     739    AssertReturn(ppVirtqBuf, VERR_INVALID_POINTER);
     740    *ppVirtqBuf = NULL;
     741
     742    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     743
     744    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
     745
     746    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[uVirtqNbr],
    801747                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    802748
     
    809755     * Allocate and initialize the descriptor chain structure.
    810756     */
    811     PVIRTIO_DESC_CHAIN_T pDescChain = (PVIRTIO_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTIO_DESC_CHAIN_T));
    812     AssertReturn(pDescChain, VERR_NO_MEMORY);
    813     pDescChain->u32Magic = VIRTIO_DESC_CHAIN_MAGIC;
    814     pDescChain->cRefs    = 1;
    815     pDescChain->uHeadIdx = uHeadIdx;
    816     *ppDescChain = pDescChain;
     757    PVIRTQBUF pVirtqBuf = (PVIRTQBUF)RTMemAllocZ(sizeof(VIRTQBUF_T));
     758    AssertReturn(pVirtqBuf, VERR_NO_MEMORY);
     759    pVirtqBuf->u32Magic = VIRTQBUF_MAGIC;
     760    pVirtqBuf->cRefs    = 1;
     761    pVirtqBuf->uHeadIdx = uHeadIdx;
     762    *ppVirtqBuf = pVirtqBuf;
    817763
    818764    /*
     
    825771    uint32_t cSegsIn = 0;
    826772    uint32_t cSegsOut = 0;
    827     PVIRTIOSGSEG paSegsIn  = pDescChain->aSegsIn;
    828     PVIRTIOSGSEG paSegsOut = pDescChain->aSegsOut;
     773    PVIRTIOSGSEG paSegsIn  = pVirtqBuf->aSegsIn;
     774    PVIRTIOSGSEG paSegsOut = pVirtqBuf->aSegsOut;
    829775
    830776    do
     
    853799        RT_UNTRUSTED_VALIDATED_FENCE();
    854800
    855         virtioReadDesc(pDevIns, pVirtio, idxVirtq, uDescIdx, &desc);
     801        virtioReadDesc(pDevIns, pVirtio, uVirtqNbr, uDescIdx, &desc);
    856802
    857803        if (desc.fFlags & VIRTQ_DESC_F_WRITE)
    858804        {
    859             Log6Func(("%s IN  desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, idxVirtq), uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
     805            Log6Func(("%s IN  desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, uVirtqNbr), uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
    860806            cbIn += desc.cb;
    861807            pSeg = &paSegsIn[cSegsIn++];
     
    863809        else
    864810        {
    865             Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, idxVirtq), uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));
     811            Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, uVirtqNbr), uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));
    866812            cbOut += desc.cb;
    867813            pSeg = &paSegsOut[cSegsOut++];
     
    884830    if (cSegsIn)
    885831    {
    886         virtioCoreSgBufInit(&pDescChain->SgBufIn, paSegsIn, cSegsIn);
    887         pDescChain->pSgPhysReturn = &pDescChain->SgBufIn;
    888         pDescChain->cbPhysReturn  = cbIn;
     832        virtioCoreSgBufInit(&pVirtqBuf->SgBufIn, paSegsIn, cSegsIn);
     833        pVirtqBuf->pSgPhysReturn = &pVirtqBuf->SgBufIn;
     834        pVirtqBuf->cbPhysReturn  = cbIn;
    889835        STAM_REL_COUNTER_ADD(&pVirtio->StatDescChainsSegsIn, cSegsIn);
    890836    }
     
    892838    if (cSegsOut)
    893839    {
    894         virtioCoreSgBufInit(&pDescChain->SgBufOut, paSegsOut, cSegsOut);
    895         pDescChain->pSgPhysSend   = &pDescChain->SgBufOut;
    896         pDescChain->cbPhysSend    = cbOut;
     840        virtioCoreSgBufInit(&pVirtqBuf->SgBufOut, paSegsOut, cSegsOut);
     841        pVirtqBuf->pSgPhysSend   = &pVirtqBuf->SgBufOut;
     842        pVirtqBuf->cbPhysSend    = cbOut;
    897843        STAM_REL_COUNTER_ADD(&pVirtio->StatDescChainsSegsOut, cSegsOut);
    898844    }
     
    904850}
    905851
    906 
    907 /**
    908  * Retains a reference to the given descriptor chain.
    909  *
    910  * @returns New reference count.
    911  * @retval  UINT32_MAX on invalid parameter.
    912  * @param   pDescChain      The descriptor chain to reference.
    913  */
    914 uint32_t virtioCoreR3DescChainRetain(PVIRTIO_DESC_CHAIN_T pDescChain)
    915 {
    916     AssertReturn(pDescChain, UINT32_MAX);
    917     AssertReturn(pDescChain->u32Magic == VIRTIO_DESC_CHAIN_MAGIC, UINT32_MAX);
    918     uint32_t cRefs = ASMAtomicIncU32(&pDescChain->cRefs);
     852/** API Function: See header file */
     853uint32_t virtioCoreR3VirtqBufRetain(PVIRTQBUF pVirtqBuf)
     854{
     855    AssertReturn(pVirtqBuf, UINT32_MAX);
     856    AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, UINT32_MAX);
     857    uint32_t cRefs = ASMAtomicIncU32(&pVirtqBuf->cRefs);
    919858    Assert(cRefs > 1);
    920859    Assert(cRefs < 16);
     
    923862
    924863
    925 /**
    926  * Releases a reference to the given descriptor chain.
    927  *
    928  * @returns New reference count.
    929  * @retval  0 if freed or invalid parameter.
    930  * @param   pVirtio         Pointer to the shared virtio state.
    931  * @param   pDescChain      The descriptor chain to reference.  NULL is quietly
    932  *                          ignored (returns 0).
    933  */
    934 uint32_t virtioCoreR3DescChainRelease(PVIRTIOCORE pVirtio, PVIRTIO_DESC_CHAIN_T pDescChain)
    935 {
    936     if (!pDescChain)
     864/** API Function: See header file */
     865uint32_t virtioCoreR3VirtqBufRelease(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf)
     866{
     867    if (!pVirtqBuf)
    937868        return 0;
    938     AssertReturn(pDescChain, 0);
    939     AssertReturn(pDescChain->u32Magic == VIRTIO_DESC_CHAIN_MAGIC, 0);
    940     uint32_t cRefs = ASMAtomicDecU32(&pDescChain->cRefs);
     869    AssertReturn(pVirtqBuf, 0);
     870    AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, 0);
     871    uint32_t cRefs = ASMAtomicDecU32(&pVirtqBuf->cRefs);
    941872    Assert(cRefs < 16);
    942873    if (cRefs == 0)
    943874    {
    944         pDescChain->u32Magic = ~VIRTIO_DESC_CHAIN_MAGIC;
    945         RTMemFree(pDescChain);
     875        pVirtqBuf->u32Magic = ~VIRTQBUF_MAGIC;
     876        RTMemFree(pVirtqBuf);
    946877        STAM_REL_COUNTER_INC(&pVirtio->StatDescChainsFreed);
    947878    }
     
    949880}
    950881
    951 
    952 /*
    953  * Notifies guest (via ISR or MSI-X) of device configuration change
    954  *
    955  * @param   pVirtio     Pointer to the shared virtio state.
    956  */
     882/** API Function: See header file */
    957883void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio)
    958884{
     
    960886}
    961887
    962 /**
    963  * Enable or Disable notification for the specified queue
    964  *
    965  * @param   pVirtio     Pointer to the shared virtio state.
    966  * @param   idxVirtq    Virtq number
    967  * @param   fEnable    Selects notification mode (enabled or disabled)
    968  */
    969 void virtioCoreVirtqNotifyEnable(PVIRTIOCORE pVirtio, uint16_t idxVirtq, bool fEnable)
     888void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable)
    970889{
    971890    if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    972891    {
    973         uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, idxVirtq);
     892        uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, uVirtqNbr);
    974893
    975894        if (fEnable)
     
    978897            fFlags |= VIRTQ_USED_F_NO_NOTIFY;
    979898
    980         virtioWriteUsedRingFlags(pVirtio->pDevInsR3, pVirtio, idxVirtq, fFlags);
    981     }
    982 }
    983 
    984 /**
    985  * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
    986  * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
    987  *
    988  * @param   pVirtio     Pointer to the virtio state.
    989  */
     899        virtioWriteUsedRingFlags(pVirtio->pDevInsR3, pVirtio, uVirtqNbr, fFlags);
     900    }
     901}
     902
     903/** API function: See Header file  */
    990904void virtioCoreResetAll(PVIRTIOCORE pVirtio)
    991905{
     
    999913}
    1000914
    1001 /**
    1002  * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor
    1003  * chain into its OUT (to device) and IN to guest components, but does NOT remove it from
    1004  * the 'avail' queue. I.e. doesn't advance the index.  This can be used with virtioVirtqSkip(),
    1005  * which *does* advance the avail index. Together they facilitate a mechanism that allows
    1006  * work with a queue element (descriptor chain) to be aborted if necessary, by not advancing
    1007  * the pointer, or, upon success calling the skip function (above) to move to the next element.
    1008  *
    1009  * Additionally it converts the OUT desc chain data to a contiguous virtual
    1010  * memory buffer for easy consumption by the caller. The caller must return the
    1011  * descriptor chain pointer via virtioCoreR3VirtqPut() and then call virtioCoreVirtqSync()
    1012  * at some point to return the data to the guest and complete the transaction.
    1013  *
    1014  * @param   pDevIns     The device instance.
    1015  * @param   pVirtio     Pointer to the shared virtio state.
    1016  * @param   idxVirtq    Virtq number
    1017  * @param   ppDescChain Address to store pointer to descriptor chain that contains the
    1018  *                      pre-processed transaction information pulled from the virtq.
    1019  *
    1020  * @returns VBox status code:
    1021  * @retval  VINF_SUCCESS         Success
    1022  * @retval  VERR_INVALID_STATE   VirtIO not in ready state (asserted).
    1023  * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
    1024  */
    1025 
    1026 int virtioCoreR3VirtqPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
    1027                          PPVIRTIO_DESC_CHAIN_T ppDescChain)
    1028 {
    1029     return virtioCoreR3VirtqGet(pDevIns, pVirtio,  idxVirtq, ppDescChain, false);
    1030 }
    1031 
    1032 /**
    1033  * Skip the next entry in the specified queue (typically used with virtioCoreR3VirtqPeek())
    1034  *
    1035  * @param   pVirtio     Pointer to the virtio state.
    1036  * @param   idxVirtq    Index of queue
    1037  */
    1038 int virtioCoreR3VirtqSkip(PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    1039 {
    1040     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    1041     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
    1042 
    1043     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[idxVirtq],
     915/** API function: See Header file  */
     916int virtioCoreR3VirtqBufPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
     917                         PPVIRTQBUF ppVirtqBuf)
     918{
     919    return virtioCoreR3VirtqBufGet(pDevIns, pVirtio,  uVirtqNbr, ppVirtqBuf, false);
     920}
     921
     922/** API function: See Header file  */
     923int virtioCoreR3VirtqBufSkip(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     924{
     925    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     926    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
     927
     928    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[uVirtqNbr],
    1044929                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    1045930
     
    1053938}
    1054939
    1055 /**
    1056  * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor
    1057  * chain into its OUT (to device) and IN to guest components.
    1058  *
    1059  * Additionally it converts the OUT desc chain data to a contiguous virtual
    1060  * memory buffer for easy consumption by the caller. The caller must return the
    1061  * descriptor chain pointer via virtioCoreR3VirtqPut() and then call virtioCoreVirtqSync()
    1062  * at some point to return the data to the guest and complete the transaction.
    1063  *
    1064  * @param   pDevIns     The device instance.
    1065  * @param   pVirtio     Pointer to the shared virtio state.
    1066  * @param   idxVirtq    Virtq number
    1067  * @param   ppDescChain Address to store pointer to descriptor chain that contains the
    1068  *                      pre-processed transaction information pulled from the virtq.
    1069  *                      Returned reference must be released by calling
    1070  *                      virtioCoreR3DescChainRelease().
    1071  * @param   fRemove     flags whether to remove desc chain from queue (false = peek)
    1072  *
    1073  * @returns VBox status code:
    1074  * @retval  VINF_SUCCESS         Success
    1075  * @retval  VERR_INVALID_STATE   VirtIO not in ready state (asserted).
    1076  * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
    1077  */
    1078 int virtioCoreR3VirtqGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
    1079                          PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove)
    1080 {
    1081     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
     940/** API function: See Header file  */
     941int virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
     942                         PPVIRTQBUF ppVirtqBuf, bool fRemove)
     943{
     944    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
    1082945
    1083946    if (IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtqState))
    1084947        return VERR_NOT_AVAILABLE;
    1085948
    1086     uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, idxVirtq, pVirtqState->uAvailIdxShadow);
     949    uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, uVirtqNbr, pVirtqState->uAvailIdxShadow);
    1087950
    1088951    if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
    1089         virtioWriteUsedAvailEvent(pDevIns,pVirtio, idxVirtq, pVirtqState->uAvailIdxShadow + 1);
     952        virtioWriteUsedAvailEvent(pDevIns,pVirtio, uVirtqNbr, pVirtqState->uAvailIdxShadow + 1);
    1090953
    1091954    if (fRemove)
    1092955        pVirtqState->uAvailIdxShadow++;
    1093956
    1094     int rc = virtioCoreR3DescChainGet(pDevIns, pVirtio, idxVirtq, uHeadIdx, ppDescChain);
     957    int rc = virtioCoreR3VirtqBufGet(pDevIns, pVirtio, uVirtqNbr, uHeadIdx, ppVirtqBuf);
    1095958    return rc;
    1096959}
    1097960
    1098 /**
    1099  * Returns data to the guest to complete a transaction initiated by virtVirtqGet().
    1100  *
    1101  * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments
    1102  * and a pointer to the descriptor chain context originally derived from the pulled
    1103  * queue entry, and this function will write the virtual memory s/g buffer into the
    1104  * guest's physical memory free the descriptor chain. The caller handles the freeing
    1105  * (as needed) of the virtual memory buffer.
    1106  *
    1107  * @note This does a write-ahead to the used ring of the guest's queue. The data
    1108  *       written won't be seen by the guest until the next call to virtioCoreVirtqSync()
    1109  *
    1110  *
    1111  * @param   pDevIns         The device instance (for reading).
    1112  * @param   pVirtio         Pointer to the shared virtio state.
    1113  * @param   idxVirtq        Virtq number
    1114  *
    1115  * @param   pSgVirtReturn   Points to scatter-gather buffer of virtual memory
    1116  *                          segments the caller is returning to the guest.
    1117  *
    1118  * @param   pDescChain      This contains the context of the scatter-gather
    1119  *                          buffer originally pulled from the queue.
    1120  *
    1121  * @param   fFence          If true, put up copy fence (memory barrier) after
    1122  *                          copying to guest phys. mem.
    1123  *
    1124  * @returns VBox status code.
    1125  * @retval  VINF_SUCCESS       Success
    1126  * @retval  VERR_INVALID_STATE VirtIO not in ready state
    1127  * @retval  VERR_NOT_AVAILABLE Virtq is empty
    1128  *
    1129  * @note    This function will not release any reference to pDescChain.  The
    1130  *          caller must take care of that.
    1131  */
    1132 int virtioCoreR3VirtqPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, PRTSGBUF pSgVirtReturn,
    1133                          PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence)
    1134 {
    1135     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    1136     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
    1137     PVIRTIOSGBUF pSgPhysReturn = pDescChain->pSgPhysReturn;
    1138 
    1139     Assert(pDescChain->u32Magic == VIRTIO_DESC_CHAIN_MAGIC);
    1140     Assert(pDescChain->cRefs > 0);
     961/** API function: See Header file  */
     962int virtioCoreR3VirtqBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, PRTSGBUF pSgVirtReturn,
     963                            PVIRTQBUF pVirtqBuf, bool fFence)
     964{
     965    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     966    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
     967    PVIRTIOSGBUF pSgPhysReturn = pVirtqBuf->pSgPhysReturn;
     968
     969    Assert(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC);
     970    Assert(pVirtqBuf->cRefs > 0);
    1141971
    1142972    AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    1143973
    1144974    Log6Func(("Copying client data to %s, desc chain (head desc_idx %d)\n",
    1145               VIRTQNAME(pVirtio, idxVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, idxVirtq)));
     975              VIRTQNAME(pVirtio, uVirtqNbr), virtioReadUsedRingIdx(pDevIns, pVirtio, uVirtqNbr)));
    1146976
    1147977    /* Copy s/g buf (virtual memory) to guest phys mem (IN direction). */
     
    11731003    /* If this write-ahead crosses threshold where the driver wants to get an event flag it */
    11741004    if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
    1175         if (pVirtqState->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxVirtq))
     1005        if (pVirtqState->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, uVirtqNbr))
    11761006            pVirtqState->fVirtqRingEventThreshold = true;
    11771007
     
    11791009     * Place used buffer's descriptor in used ring but don't update used ring's slot index.
    11801010     * That will be done with a subsequent client call to virtioCoreVirtqSync() */
    1181     virtioWriteUsedElem(pDevIns, pVirtio, idxVirtq, pVirtqState->uUsedIdxShadow++, pDescChain->uHeadIdx, (uint32_t)cbTotal);
     1011    virtioWriteUsedElem(pDevIns, pVirtio, uVirtqNbr, pVirtqState->uUsedIdxShadow++, pVirtqBuf->uHeadIdx, (uint32_t)cbTotal);
    11821012
    11831013    if (pSgVirtReturn)
    11841014        Log6Func((".... Copied %zu bytes in %d segs to %u byte buffer, residual=%zu\n",
    1185                   cbTotal - cbRemain, pSgVirtReturn->cSegs, pDescChain->cbPhysReturn, pDescChain->cbPhysReturn - cbTotal));
     1015                  cbTotal - cbRemain, pSgVirtReturn->cSegs, pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal));
    11861016
    11871017    Log6Func(("Write ahead used_idx=%u, %s used_idx=%u\n",
    1188               pVirtqState->uUsedIdxShadow, VIRTQNAME(pVirtio, idxVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, idxVirtq)));
     1018              pVirtqState->uUsedIdxShadow, VIRTQNAME(pVirtio, uVirtqNbr), virtioReadUsedRingIdx(pDevIns, pVirtio, uVirtqNbr)));
    11891019
    11901020    return VINF_SUCCESS;
     
    11931023#endif /* IN_RING3 */
    11941024
     1025/** API function: See Header file  */
     1026int virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     1027{
     1028    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     1029    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
     1030
     1031    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[uVirtqNbr],
     1032                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
     1033
     1034    Log6Func(("Updating %s used_idx to %u\n",
     1035              VIRTQNAME(pVirtio, uVirtqNbr), pVirtqState->uUsedIdxShadow));
     1036
     1037    virtioWriteUsedRingIdx(pDevIns, pVirtio, uVirtqNbr, pVirtqState->uUsedIdxShadow);
     1038    virtioCoreNotifyGuestDriver(pDevIns, pVirtio, uVirtqNbr);
     1039
     1040    return VINF_SUCCESS;
     1041}
     1042
     1043
    11951044/**
    1196  * Updates the indicated virtq's "used ring" descriptor index to match the
    1197  * current write-head index, thus exposing the data added to the used ring by all
    1198  * virtioCoreR3VirtqPut() calls since the last sync. This should be called after one or
    1199  * more virtioCoreR3VirtqPut() calls to inform the guest driver there is data in the queue.
    1200  * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest,
    1201  * depending on VirtIO features negotiated and conditions, otherwise the guest
    1202  * will detect the update by polling. (see VirtIO 1.0 specification, Section 2.4 "Virtqueues").
    1203  *
    1204  * @param   pDevIns     The device instance.
    1205  * @param   pVirtio     Pointer to the shared virtio state.
    1206  * @param   idxVirtq    Virtq number
    1207  *
    1208  * @returns VBox status code.
    1209  * @retval  VINF_SUCCESS       Success
    1210  * @retval  VERR_INVALID_STATE VirtIO not in ready state
    1211  */
    1212 int virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    1213 {
    1214     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    1215     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
    1216 
    1217     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[idxVirtq],
    1218                     ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    1219 
    1220     Log6Func(("Updating %s used_idx to %u\n",
    1221               VIRTQNAME(pVirtio, idxVirtq), pVirtqState->uUsedIdxShadow));
    1222 
    1223     virtioWriteUsedRingIdx(pDevIns, pVirtio, idxVirtq, pVirtqState->uUsedIdxShadow);
    1224     virtioCoreNotifyGuestDriver(pDevIns, pVirtio, idxVirtq);
    1225 
    1226     return VINF_SUCCESS;
    1227 }
    1228 
    1229 
    1230 /**
    1231  */
    1232 static void virtioCoreVirtqNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint16_t uNotifyIdx)
     1045 */
     1046static void virtioCoreVirtqNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint16_t uNotifyIdx)
    12331047{
    12341048
    12351049    PVIRTIOCORECC pVirtioCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
    12361050
    1237     /* See VirtIO 1.0, section 4.1.5.2 It implies that idxVirtq and uNotifyIdx should match.
     1051    /* See VirtIO 1.0, section 4.1.5.2 It implies that uVirtqNbr and uNotifyIdx should match.
    12381052     * Disregarding this notification may cause throughput to stop, however there's no way to know
    12391053     * which was queue was intended for wake-up if the two parameters disagree. */
    12401054
    1241     AssertMsg(uNotifyIdx == idxVirtq,
     1055    AssertMsg(uNotifyIdx == uVirtqNbr,
    12421056                    ("Guest kicked virtq %d's notify addr w/non-corresponding virtq idx %d\n",
    1243                      idxVirtq, uNotifyIdx));
     1057                     uVirtqNbr, uNotifyIdx));
    12441058    RT_NOREF(uNotifyIdx);
    12451059
    1246     AssertReturnVoid(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
     1060    AssertReturnVoid(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
    12471061    Log6Func(("%s (desc chains: %u)\n",
    1248         pVirtio->aVirtqState[idxVirtq].szVirtqName,
    1249         virtioCoreVirtqAvailCount(pDevIns, pVirtio, idxVirtq)));
     1062        pVirtio->aVirtqState[uVirtqNbr].szVirtqName,
     1063        virtioCoreVirtqAvailCount(pDevIns, pVirtio, uVirtqNbr)));
    12501064
    12511065    /* Inform client */
    1252     pVirtioCC->pfnVirtqNotified(pDevIns, pVirtio, idxVirtq);
     1066    pVirtioCC->pfnVirtqNotified(pDevIns, pVirtio, uVirtqNbr);
    12531067}
    12541068
     
    12621076 * @param   pDevIns     The device instance.
    12631077 * @param   pVirtio     Pointer to the shared virtio state.
    1264  * @param   idxVirtq    Virtq to check for guest interrupt handling preference
    1265  */
    1266 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    1267 {
    1268 
    1269     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    1270     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
     1078 * @param   uVirtqNbr    Virtq to check for guest interrupt handling preference
     1079 */
     1080static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     1081{
     1082
     1083    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     1084    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
    12711085
    12721086    if (!IS_DRIVER_OK(pVirtio))
     
    12821096#ifdef IN_RING3
    12831097            Log6Func(("...kicking guest %s, VIRTIO_F_EVENT_IDX set and threshold (%d) reached\n",
    1284                    VIRTQNAME(pVirtio, idxVirtq), (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, idxVirtq)));
     1098                   VIRTQNAME(pVirtio, uVirtqNbr), (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, uVirtqNbr)));
    12851099#endif
    1286             virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[idxVirtq]);
     1100            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[uVirtqNbr]);
    12871101            pVirtqState->fVirtqRingEventThreshold = false;
    12881102            return;
     
    12901104#ifdef IN_RING3
    12911105        Log6Func(("...skip interrupt %s, VIRTIO_F_EVENT_IDX set but threshold (%d) not reached (%d)\n",
    1292                    VIRTQNAME(pVirtio, idxVirtq),(uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, idxVirtq), pVirtqState->uUsedIdxShadow));
     1106                   VIRTQNAME(pVirtio, uVirtqNbr),(uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, uVirtqNbr), pVirtqState->uUsedIdxShadow));
    12931107#endif
    12941108    }
     
    12961110    {
    12971111        /** If guest driver hasn't suppressed interrupts, interrupt  */
    1298         if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, idxVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT))
    1299         {
    1300             virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[idxVirtq]);
     1112        if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, uVirtqNbr) & VIRTQ_AVAIL_F_NO_INTERRUPT))
     1113        {
     1114            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[uVirtqNbr]);
    13011115            return;
    13021116        }
    13031117        Log6Func(("...skipping interrupt for %s (guest set VIRTQ_AVAIL_F_NO_INTERRUPT)\n",
    1304                      VIRTQNAME(pVirtio, idxVirtq)));
     1118                     VIRTQNAME(pVirtio, uVirtqNbr)));
    13051119    }
    13061120}
     
    13471161
    13481162#ifdef IN_RING3
    1349 static void virtioResetVirtq(PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    1350 {
    1351     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    1352     PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq];
     1163static void virtioResetVirtq(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     1164{
     1165    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     1166    PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr];
    13531167    pVirtqState->uAvailIdxShadow = 0;
    13541168    pVirtqState->uUsedIdxShadow  = 0;
    13551169    pVirtqState->fVirtqRingEventThreshold = false;
    1356     pVirtio->uVirtqEnable[idxVirtq] = false;
    1357     pVirtio->uVirtqSize[idxVirtq] = VIRTQ_MAX_ENTRIES;
    1358     pVirtio->uVirtqNotifyOff[idxVirtq] = idxVirtq;
    1359     pVirtio->uVirtqMsixVector[idxVirtq] = idxVirtq + 2;
     1170    pVirtio->uVirtqEnable[uVirtqNbr] = false;
     1171    pVirtio->uVirtqSize[uVirtqNbr] = VIRTQ_MAX_ENTRIES;
     1172    pVirtio->uVirtqNotifyOff[uVirtqNbr] = uVirtqNbr;
     1173    pVirtio->uVirtqMsixVector[uVirtqNbr] = uVirtqNbr + 2;
    13601174    if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */
    1361         pVirtio->uVirtqMsixVector[idxVirtq] = VIRTIO_MSI_NO_VECTOR;
    1362 
    1363     virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtio->uVirtqMsixVector[idxVirtq]);
     1175        pVirtio->uVirtqMsixVector[uVirtqNbr] = VIRTIO_MSI_NO_VECTOR;
     1176
     1177    virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtio->uVirtqMsixVector[uVirtqNbr]);
    13641178}
    13651179
     
    13881202        pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR;
    13891203
    1390     for (uint16_t idxVirtq = 0; idxVirtq < VIRTQ_MAX_CNT; idxVirtq++)
    1391         virtioResetVirtq(pVirtio, idxVirtq);
     1204    for (uint16_t uVirtqNbr = 0; uVirtqNbr < VIRTQ_MAX_CNT; uVirtqNbr++)
     1205        virtioResetVirtq(pVirtio, uVirtqNbr);
    13921206}
    13931207
     
    20261840            break;
    20271841        case kvirtIoVmStateChangedResume:
    2028             virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* idxVirtq */);
     1842            virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* uVirtqNbr */);
    20291843            break;
    20301844        default:
  • trunk/src/VBox/Devices/VirtIO/VirtioCore.h

    r84818 r84819  
    11/* $Id$ */
     2
    23/** @file
    3  * Virtio_1_0.h - Virtio Declarations
     4 * VirtioCore.h - Virtio Declarations
    45 */
    56
     
    9394
    9495/**
    95  * Virtio descriptor chain representation.
    96  */
    97 typedef struct VIRTIO_DESC_CHAIN
    98 {
    99     uint32_t            u32Magic;                                   /**< Magic value, VIRTIO_DESC_CHAIN_MAGIC.    */
     96 * VirtIO buffers are actually descriptor chains. VirtIO's scatter-gather architecture
     97 * defines a head descriptor (index into ring of descriptors), which is chained to 0 or more
     98 * other descriptors that can optionally continue the chain.  This structure is VirtualBox's
     99 * Virtq buffer representation, which contains a reference to the head desc chain idx and
     100 * context for working with virtq buffers.
     101 */
     102typedef struct VIRTQBUF
     103{
     104    uint32_t            u32Magic;                                   /**< Magic value, VIRTQBUF_MAGIC.    */
    100105    uint32_t volatile   cRefs;                                      /**< Reference counter. */
    101106    uint32_t            uHeadIdx;                                   /**< Head idx of associated desc chain        */
     
    112117    VIRTIOSGSEG         aSegsOut[VIRTQ_MAX_ENTRIES];
    113118    /** @} */
    114 } VIRTIO_DESC_CHAIN_T;
    115 /** Pointer to a Virtio descriptor chain. */
    116 typedef VIRTIO_DESC_CHAIN_T *PVIRTIO_DESC_CHAIN_T;
    117 /** Pointer to a Virtio descriptor chain pointer. */
    118 typedef VIRTIO_DESC_CHAIN_T **PPVIRTIO_DESC_CHAIN_T;
    119 /** Magic value for VIRTIO_DESC_CHAIN_T::u32Magic. */
    120 #define VIRTIO_DESC_CHAIN_MAGIC             UINT32_C(0x19600219)
     119} VIRTQBUF_T;
     120
     121/** Pointers to a Virtio descriptor chain. */
     122typedef VIRTQBUF_T *PVIRTQBUF, **PPVIRTQBUF;
     123/** Magic value for VIRTQBUF_T::u32Magic. */
     124#define VIRTQBUF_MAGIC             UINT32_C(0x19600219)
    121125
    122126typedef struct VIRTIOPCIPARAMS
     
    187191typedef struct VIRTQSTATE
    188192{
    189     uint16_t  idxVirtq;                                          /**< Index of this queue                       */
     193    uint16_t  uVirtqNbr;                                          /**< Index of this queue                       */
    190194    char      szVirtqName[32];                                   /**< Dev-specific name of queue                */
    191195    uint16_t  uAvailIdxShadow;                                   /**< Consumer's position in avail ring         */
     
    348352     * @param   pVirtio    Pointer to the shared virtio state.
    349353     * @param   pVirtioCC  Pointer to the ring-3 virtio state.
    350      * @param   idxVirtq   Index of the notified queue
     354     * @param   uVirtqNbr   Index of the notified queue
    351355     */
    352     DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);
     356    DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
    353357
    354358    /** @} */
     
    381385     * @param   pVirtio    Pointer to the shared virtio state.
    382386     * @param   pVirtioCC  Pointer to the ring-3 virtio state.
    383      * @param   idxVirtq   Index of the notified queue
     387     * @param   uVirtqNbr   Index of the notified queue
    384388     */
    385     DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);
     389    DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
    386390
    387391} VIRTIOCORER0;
     
    405409 * @{ */
    406410
    407 int      virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);
    408 uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);
    409 void     virtioCoreVirtqEnable(PVIRTIOCORE pVirtio, uint16_t idxVirtq, bool fEnable);
    410 void     virtioCoreVirtqNotifyEnable(PVIRTIOCORE pVirtio, uint16_t idxVirtq, bool fEnable);
     411
     412/**
     413 * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
     414 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
     415 *
     416 * @param   pVirtio     Pointer to the virtio state.
     417 */
     418void     virtioCoreResetAll(PVIRTIOCORE pVirtio);
     419
     420/**
     421 * 'Attaches' the inheriting device-specific code's queue state to the VirtIO core
     422 * queue management, informing the core of the name of the queue and number. The VirtIO core
     423 * allocates the queue state information so it can handle all the core VirtiIO queue operations
     424 * and dispatch callbacks, etc...
     425 *
     426 * @param   pVirtio     Pointer to the shared virtio state.
     427 * @param   uVirtqNbr    Virtq number
     428 * @param   pcszName    Name to give queue
     429 *
     430 * @returns VBox status code.
     431 */
     432int      virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, const char *pcszName);
     433
     434/**
     435 * Enables or disables a virtq
     436 *
     437 * @param   pVirtio     Pointer to the shared virtio state.
     438 * @param   uVirtqNbr   Virtq number
     439 * @param   fEnable     Flags whether to enable or disable the virtq
     440 *
     441 */
     442
     443void     virtioCoreVirtqEnable(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable);
     444
     445/**
     446 * Enable or Disable notification for the specified queue
     447 *
     448 * @param   pVirtio     Pointer to the shared virtio state.
     449 * @param   uVirtqNbr    Virtq number
     450 * @param   fEnable    Selects notification mode (enabled or disabled)
     451 */
     452void     virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable);
     453
     454/*
     455 * Notifies guest (via ISR or MSI-X) of device configuration change
     456 *
     457 * @param   pVirtio     Pointer to the shared virtio state.
     458 */
    411459void     virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio);
    412 void     virtioCoreResetAll(PVIRTIOCORE pVirtio);
     460
     461/*
     462 * Displays the VirtIO spec-related features offered by the core component,
     463 * as well as which features have been negotiated and accepted or declined by the guest driver,
     464 * providing a summary view of the configuration the device is operating with.
     465 *
     466 * @param   pVirtio     Pointer to the shared virtio state.
     467 * @param   pHlp        Pointer to the debug info hlp struct
     468 */
    413469void     virtioCorePrintFeatures(VIRTIOCORE *pVirtio, PCDBGFINFOHLP pHlp);
    414470
    415 uint32_t virtioCoreR3DescChainRetain(PVIRTIO_DESC_CHAIN_T pDescChain);
    416 uint32_t virtioCoreR3DescChainRelease(PVIRTIOCORE pVirtio, PVIRTIO_DESC_CHAIN_T pDescChain);
    417 void     virtioCoreR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs);
    418 void     virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int idxVirtq);
    419 int      virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t idxVirtq, const char *pcszName);
    420 
    421 int      virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
    422                                   uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain);
    423 
    424 int      virtioCoreR3VirtqPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
    425                                PPVIRTIO_DESC_CHAIN_T ppDescChain);
    426 
    427 int      virtioCoreR3VirtqSkip(PVIRTIOCORE pVirtio, uint16_t idxVirtq);
    428 
    429 int      virtioCoreR3VirtqGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,
    430                               PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove);
    431 
    432 int      virtioCoreR3VirtqPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, PRTSGBUF pSgVirtReturn,
    433                               PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence);
    434 
     471/*
     472 * Debuging assist feature displays the state of the VirtIO core code, which includes
     473 * an overview of the state of all of the queues.
     474 *
     475 * This can be invoked when running the VirtualBox debugger, or from the command line
     476 * using the command: "VboxManage debugvm <VM name or id> info <device name> [args]"
     477 *
     478 * Example:  VBoxManage debugvm myVnetVm info "virtio-net" all
     479 *
     480 * This is implemented currently to be invoked by the inheriting device-specific code
     481 * (see DevVirtioNet for an example, which receives the debugvm command directly).
     482 * That devices lists the available sub-options if no arguments are provided. In that
     483 * example this virtq info related function is invoked hierarchically when virtio-net
     484 * displays its device-specific queue info.
     485 *
     486 * @param   pDevIns     The device instance.
     487 * @param   pHlp        Pointer to the debug info hlp struct
     488 * @param   pszArgs     Arguments to function
     489 */
     490void     virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int uVirtqNbr);
     491
     492/*
     493 * Returns the number of avail bufs in the virtq.
     494 *
     495 * @param   pDevIns     The device instance.
     496 * @param   pVirtio     Pointer to the shared virtio state.
     497 * @param   uVirtqNbr   Virtqueue to return the count of buffers available for.
     498 */
     499uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
     500
     501/**
     502 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor
     503 * chain into its OUT (to device) and IN to guest components, but does NOT remove it from
     504 * the 'avail' queue. I.e. doesn't advance the index.  This can be used with virtioVirtqSkip(),
     505 * which *does* advance the avail index. Together they facilitate a mechanism that allows
     506 * work with a queue element (descriptor chain) to be aborted if necessary, by not advancing
     507 * the pointer, or, upon success calling the skip function (above) to move to the next element.
     508 *
     509 * Additionally it converts the OUT desc chain data to a contiguous virtual
     510 * memory buffer for easy consumption by the caller. The caller must return the
     511 * descriptor chain pointer via virtioCoreR3VirtqBufPut() and then call virtioCoreVirtqSync()
     512 * at some point to return the data to the guest and complete the transaction.
     513 *
     514 * @param   pDevIns     The device instance.
     515 * @param   pVirtio     Pointer to the shared virtio state.
     516 * @param   uVirtqNbr   Virtq number
     517 * @param   ppVirtqBuf Address to store pointer to descriptor chain that contains the
     518 *                      pre-processed transaction information pulled from the virtq.
     519 *
     520 * @returns VBox status code:
     521 * @retval  VINF_SUCCESS         Success
     522 * @retval  VERR_INVALID_STATE   VirtIO not in ready state (asserted).
     523 * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
     524 */
     525int      virtioCoreR3VirtqBufPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
     526                                  PPVIRTQBUF ppVirtqBuf);
     527
     528/**
     529 * Fetches the next descriptor chain using avail ring of indicated queue and converts the descriptor
     530 * chain into its OUT (to device) and IN to guest components.
     531 *
     532 * Additionally it converts the OUT desc chain data to a contiguous virtual
     533 * memory buffer for easy consumption by the caller. The caller must return the
     534 * descriptor chain pointer via virtioCoreR3VirtqBufPut() and then call virtioCoreVirtqSync()
     535 * at some point to return the data to the guest and complete the transaction.
     536 *
     537 * @param   pDevIns     The device instance.
     538 * @param   pVirtio     Pointer to the shared virtio state.
     539 * @param   uVirtqNbr    Virtq number
     540 * @param   ppVirtqBuf Address to store pointer to descriptor chain that contains the
     541 *                      pre-processed transaction information pulled from the virtq.
     542 *                      Returned reference must be released by calling
     543 *                      virtioCoreR3VirtqBufRelease().
     544 * @param   fRemove     flags whether to remove desc chain from queue (false = peek)
     545 *
     546 * @returns VBox status code:
     547 * @retval  VINF_SUCCESS         Success
     548 * @retval  VERR_INVALID_STATE   VirtIO not in ready state (asserted).
     549 * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
     550 */
     551int      virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
     552                                 PPVIRTQBUF ppVirtqBuf, bool fRemove);
     553
     554
     555/**
     556 * Fetches a specific descriptor chain using avail ring of indicated queue and converts the descriptor
     557 * chain into its OUT (to device) and IN to guest components.
     558 *
     559 * Additionally it converts the OUT desc chain data to a contiguous virtual
     560 * memory buffer for easy consumption by the caller. The caller must return the
     561 * descriptor chain pointer via virtioCoreR3VirtqBufPut() and then call virtioCoreVirtqSync()
     562 * at some point to return the data to the guest and complete the transaction.
     563 *
     564 * @param   pDevIns     The device instance.
     565 * @param   pVirtio     Pointer to the shared virtio state.
     566 * @param   uVirtqNbr    Virtq number
     567 * @param   ppVirtqBuf Address to store pointer to descriptor chain that contains the
     568 *                      pre-processed transaction information pulled from the virtq.
     569 *                      Returned reference must be released by calling
     570 *                      virtioCoreR3VirtqBufRelease().
     571 * @param   fRemove     flags whether to remove desc chain from queue (false = peek)
     572 *
     573 * @returns VBox status code:
     574 * @retval  VINF_SUCCESS         Success
     575 * @retval  VERR_INVALID_STATE   VirtIO not in ready state (asserted).
     576 * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
     577 */
     578
     579int      virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr,
     580                                  uint16_t uHeadIdx, PPVIRTQBUF ppVirtqBuf);
     581
     582/**
     583 * Returns data to the guest to complete a transaction initiated by virtVirtqGet().
     584 *
     585 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments
     586 * and a pointer to the descriptor chain context originally derived from the pulled
     587 * queue entry, and this function will write the virtual memory s/g buffer into the
     588 * guest's physical memory free the descriptor chain. The caller handles the freeing
     589 * (as needed) of the virtual memory buffer.
     590 *
     591 * @note This does a write-ahead to the used ring of the guest's queue. The data
     592 *       written won't be seen by the guest until the next call to virtioCoreVirtqSync()
     593 *
     594 *
     595 * @param   pDevIns         The device instance (for reading).
     596 * @param   pVirtio         Pointer to the shared virtio state.
     597 * @param   uVirtqNbr        Virtq number
     598 *
     599 * @param   pSgVirtReturn   Points to scatter-gather buffer of virtual memory
     600 *                          segments the caller is returning to the guest.
     601 *
     602 * @param   pVirtqBuf      This contains the context of the scatter-gather
     603 *                          buffer originally pulled from the queue.
     604 *
     605 * @param   fFence          If true, put up copy fence (memory barrier) after
     606 *                          copying to guest phys. mem.
     607 *
     608 * @returns VBox status code.
     609 * @retval  VINF_SUCCESS       Success
     610 * @retval  VERR_INVALID_STATE VirtIO not in ready state
     611 * @retval  VERR_NOT_AVAILABLE Virtq is empty
     612 *
     613 * @note    This function will not release any reference to pVirtqBuf.  The
     614 *          caller must take care of that.
     615 */
     616
     617int      virtioCoreR3VirtqBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, PRTSGBUF pSgVirtReturn,
     618                                 PVIRTQBUF pVirtqBuf, bool fFence);
     619
     620/**
     621 * Skip the next entry in the specified queue (typically used with virtioCoreR3VirtqBufPeek())
     622 *
     623 * @param   pVirtio     Pointer to the virtio state.
     624 * @param   uVirtqNbr    Index of queue
     625 */
     626int      virtioCoreR3VirtqBufSkip(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
     627
     628/**
     629 * Updates the indicated virtq's "used ring" descriptor index to match the
     630 * current write-head index, thus exposing the data added to the used ring by all
     631 * virtioCoreR3VirtqBufPut() calls since the last sync. This should be called after one or
     632 * more virtioCoreR3VirtqBufPut() calls to inform the guest driver there is data in the queue.
     633 * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest,
     634 * depending on VirtIO features negotiated and conditions, otherwise the guest
     635 * will detect the update by polling. (see VirtIO 1.0 specification, Section 2.4 "Virtqueues").
     636 *
     637 * @param   pDevIns     The device instance.
     638 * @param   pVirtio     Pointer to the shared virtio state.
     639 * @param   uVirtqNbr   Virtq number
     640 *
     641 * @returns VBox status code.
     642 * @retval  VINF_SUCCESS       Success
     643 * @retval  VERR_INVALID_STATE VirtIO not in ready state
     644 */
     645int      virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
     646
     647/**
     648 * Retains a reference to the given descriptor chain.
     649 *
     650 * @returns New reference count.
     651 * @retval  UINT32_MAX on invalid parameter.
     652 * @param   pVirtqBuf      The descriptor chain to reference.
     653 */
     654uint32_t virtioCoreR3VirtqBufRetain(PVIRTQBUF pVirtqBuf);
     655
     656/**
     657 * Releases a reference to the given descriptor chain.
     658 *
     659 * @returns New reference count.
     660 * @retval  0 if freed or invalid parameter.
     661 * @param   pVirtio         Pointer to the shared virtio state.
     662 * @param   pVirtqBuf       The descriptor chain to reference.  NULL is quietly
     663 *                          ignored (returns 0).
     664 */
     665uint32_t virtioCoreR3VirtqBufRelease(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf);
    435666
    436667/**
     
    438669 *
    439670 * @param   pVirtio     Pointer to the virtio state.
    440  * @param   idxVirtq    Virtq number.
    441  * @returns   true or false indicating whether to enable queue or not
    442  */
    443 DECLINLINE(bool) virtioCoreIsVirtqEnabled(PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    444 {
    445     Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    446     return pVirtio->uVirtqEnable[idxVirtq] != 0;
     671 * @param   uVirtqNbr    Virtq number.
     672 * @returns true or false indicating whether to enable queue or not
     673 */
     674DECLINLINE(bool) virtioCoreIsVirtqEnabled(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     675{
     676    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     677    return pVirtio->uVirtqEnable[uVirtqNbr] != 0;
    447678}
    448679
    449680/**
    450  * Get name of queue, by idxVirtq, assigned at virtioCoreR3VirtqAttach()
     681 * Get name of queue, by uVirtqNbr, assigned at virtioCoreR3VirtqAttach()
    451682 *
    452683 * @param   pVirtio     Pointer to the virtio state.
    453  * @param   idxVirtq    Virtq number.
     684 * @param   uVirtqNbr    Virtq number.
    454685 *
    455686 * @returns Pointer to read-only queue name.
    456687 */
    457 DECLINLINE(const char *) virtioCoreVirtqGetName(PVIRTIOCORE pVirtio, uint16_t idxVirtq)
    458 {
    459     Assert((size_t)idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState));
    460     return pVirtio->aVirtqState[idxVirtq].szVirtqName;
     688DECLINLINE(const char *) virtioCoreVirtqGetName(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     689{
     690    Assert((size_t)uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState));
     691    return pVirtio->aVirtqState[uVirtqNbr].szVirtqName;
    461692}
    462693
     
    470701    return pVirtio->uDriverFeatures;
    471702}
    472 
    473703
    474704/**
     
    486716}
    487717
    488 void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
     718/**
     719 * Log memory-mapped I/O input or output value.
     720 *
     721 * This is to be invoked by macros that assume they are invoked in functions with
     722 * the relevant arguments. (See Virtio_1_0.cpp).
     723 *
     724 * It is exposed via the API so inheriting device-specific clients can provide similar
     725 * logging capabilities for a consistent look-and-feel.
     726 *
     727 * @param   pszFunc     To avoid displaying this function's name via __FUNCTION__ or LogFunc()
     728 * @param   pszMember   Name of struct member
     729 * @param   pv          pointer to value
     730 * @param   cb          size of value
     731 * @param   uOffset     offset into member where value starts
     732 * @param   fWrite      True if write I/O
     733 * @param   fHasIndex   True if the member is indexed
     734 * @param   idx         The index if fHasIndex
     735 */
     736const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState);void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
    489737                                const void *pv, uint32_t cb, uint32_t uOffset,
    490738                                int fWrite, int fHasIndex, uint32_t idx);
    491739
    492 /* Debug assist functions for consumer device code */
     740/**
     741 * Debug assist for any consumer device code that inherits VIRTIOCORE
     742 *
     743 * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to
     744 * control enabling of logging efficiently.
     745 *
     746 * @param   pv          pointer to buffer to dump contents of
     747 * @param   cb          count of characters to dump from buffer
     748 * @param   uBase       base address of per-row address prefixing of hex output
     749 * @param   pszTitle    Optional title. If present displays title that lists
     750 *                      provided text with value of cb to indicate size next to it.
     751 */
    493752void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle);
     753
     754/**
     755 * Debug assist for any consumer device code that inherits VIRTIOCORE
     756&
     757 * Do a hex dump of memory in guest physical context
     758 *
     759 * @param   GCPhys      pointer to buffer to dump contents of
     760 * @param   cb          count of characters to dump from buffer
     761 * @param   uBase       base address of per-row address prefixing of hex output
     762 * @param   pszTitle    Optional title. If present displays title that lists
     763 *                      provided text with value of cb to indicate size next to it.
     764 */
    494765void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle);
    495766
    496 
     767/** The following virtioCoreSgBuf*() functions mimic the functionality of the related RT s/g functions,
     768 *  except they work with the data type GCPhys rather than void *
     769 */
    497770void     virtioCoreSgBufInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs);
    498771void     virtioCoreSgBufReset(PVIRTIOSGBUF pGcSgBuf);
     
    504777size_t   virtioCoreSgBufCalcTotalLength(PVIRTIOSGBUF pGcSgBuf);
    505778
     779/** Misc VM and PDM boilerplate */
    506780int      virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
    507781int      virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
     
    511785                      const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg);
    512786int      virtioCoreRZInit(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio);
     787
     788
    513789const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState);
    514790
Note: See TracChangeset for help on using the changeset viewer.

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