VirtualBox

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


Ignore:
Timestamp:
Sep 13, 2019 2:33:47 AM (5 years ago)
Author:
vboxsync
Message:

Storage/DevVirtioSCSI.cpp: Added multi-target support. See bugref:9440, Comment #90

Location:
trunk/src/VBox/Devices/VirtIO
Files:
3 edited

Legend:

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

    r80718 r80762  
    3434
    3535#define INSTANCE(pVirtio) pVirtio->szInstance
    36 #define QUEUENAME(qIdx) (pVirtio->virtqProxy[qIdx].szVirtqName)
    37 
     36#define QUEUENAME(qIdx) (pVirtio->virtqState[qIdx].szVirtqName)
     37
     38/**
     39 * See API comments in header file for description
     40 */
     41void virtioVirtToSgPhys(VIRTIOHANDLE hVirtio, PRTSGBUF pSgDst, void *pvSrc, size_t cb)
     42{
     43    while (cb)
     44    {
     45        size_t cbSeg = cb;
     46        RTGCPHYS GCPhys = (RTGCPHYS)RTSgBufGetNextSegment(pSgDst, &cbSeg);
     47        PDMDevHlpPhysWrite(((PVIRTIOSTATE)hVirtio)->CTX_SUFF(pDevIns), GCPhys, pvSrc, cbSeg);
     48        pvSrc = ((uint8_t *)pvSrc) + cbSeg;
     49        cb -= cbSeg;
     50    }
     51}
     52
     53/**
     54 * See API comments in header file for description
     55 */
     56void virtioSgPhysToVirt(VIRTIOHANDLE hVirtio, PRTSGBUF pSgSrc, void *pvDst, size_t cb)
     57{
     58    while (cb)
     59    {
     60        size_t cbSeg = cb;
     61        RTGCPHYS GCPhys = (RTGCPHYS)RTSgBufGetNextSegment(pSgSrc, &cbSeg);
     62        PDMDevHlpPhysRead(((PVIRTIOSTATE)hVirtio)->CTX_SUFF(pDevIns), GCPhys, pvDst, cbSeg);
     63        pvDst = ((uint8_t *)pvDst) + cbSeg;
     64        cb -= cbSeg;
     65    }
     66}
    3867
    3968/**
     
    4473    LogFunc(("%s\n", pcszName));
    4574    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    46     PVIRTQ_PROXY_T pVirtqProxy = &(pVirtio->virtqProxy[qIdx]);
    47     pVirtqProxy->pDescChain = (PVIRTQ_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTQ_DESC_CHAIN_T));
    48     if (!pVirtqProxy->pDescChain)
    49     {
    50         Log(("Out of memory!"));
    51         return VERR_NO_MEMORY;
    52     }
    53     pVirtqProxy->uAvailIdx = 0;
    54     pVirtqProxy->uUsedIdx  = 0;
    55     pVirtqProxy->fEventThresholdReached = false;
    56     RTStrCopy((char *)pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName), pcszName);
     75    PVIRTQSTATE  pVirtq  = &(pVirtio->virtqState[qIdx]);
     76    pVirtq->uAvailIdx = 0;
     77    pVirtq->uUsedIdx  = 0;
     78    pVirtq->fEventThresholdReached = false;
     79    RTStrCopy((char *)pVirtq->szVirtqName, sizeof(pVirtq->szVirtqName), pcszName);
    5780    return VINF_SUCCESS;
    5881
     
    6487const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    6588{
    66     return (const char *)((PVIRTIOSTATE)hVirtio)->virtqProxy[qIdx].szVirtqName;
     89    return (const char *)((PVIRTIOSTATE)hVirtio)->virtqState[qIdx].szVirtqName;
    6790}
    6891
     
    7295int virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    7396{
    74     Assert(qIdx < sizeof(VIRTQ_PROXY_T));
     97    Assert(qIdx < sizeof(VIRTQSTATE));
    7598
    7699    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    77     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     100    PVIRTQSTATE  pVirtq  = &pVirtio->virtqState[qIdx];
    78101
    79102    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     
    83106        return VERR_NOT_AVAILABLE;
    84107
    85     Log2Func(("%s avail_idx=%u\n", pVirtqProxy->szVirtqName, pVirtqProxy->uAvailIdx));
    86     pVirtqProxy->uAvailIdx++;
     108    Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx));
     109    pVirtq->uAvailIdx++;
    87110
    88111    return VINF_SUCCESS;
     
    112135 * See API comments in header file for description
    113136 */
    114 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs)
    115 {
    116     return virtioQueueGet(hVirtio, qIdx, false /* fRemove */, ppInSegs, ppOutSegs);
    117 }
    118 
    119  /*/**
    120  * See API comments in header file for description
    121  */
    122 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove,
    123                 PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs)
    124 {
     137int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain,  bool fRemove)
     138{
     139    Assert(ppDescChain);
     140
    125141    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    126     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
    127     PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;
     142    PVIRTQSTATE  pVirtq  = &pVirtio->virtqState[qIdx];
     143
     144    PRTSGSEG paSegsIn = (PRTSGSEG)RTMemAlloc(VIRTQ_MAX_SIZE * sizeof(RTSGSEG));
     145    AssertReturn(paSegsIn, VERR_NO_MEMORY);
     146
     147    PRTSGSEG paSegsOut = (PRTSGSEG)RTMemAlloc(VIRTQ_MAX_SIZE * sizeof(RTSGSEG));
     148    AssertReturn(paSegsOut, VERR_NO_MEMORY);
    128149
    129150    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     
    133154        return VERR_NOT_AVAILABLE;
    134155
    135     pDescChain->cSegsIn = pDescChain->cSegsOut = 0;
    136 
    137     pDescChain->uHeadIdx = virtioReadAvailDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx);
    138     uint16_t uDescIdx = pDescChain->uHeadIdx;
     156    uint16_t uHeadIdx = virtioReadAvailDescIdx(pVirtio, qIdx, pVirtq->uAvailIdx);
     157    uint16_t uDescIdx = uHeadIdx;
    139158
    140159    Log6Func(("%s DESC CHAIN: (head) desc_idx=%u [avail_idx=%u]\n",
    141             pVirtqProxy->szVirtqName, pDescChain->uHeadIdx, pVirtqProxy->uAvailIdx));
     160            pVirtq->szVirtqName, uHeadIdx, pVirtq->uAvailIdx));
    142161
    143162    if (fRemove)
    144         pVirtqProxy->uAvailIdx++;
    145 
    146     uint32_t cbIn = 0, cbOut = 0;
     163        pVirtq->uAvailIdx++;
     164
    147165    VIRTQ_DESC_T desc;
     166
     167    uint32_t cbIn = 0, cbOut = 0, cSegsIn = 0, cSegsOut = 0;
     168
    148169    do
    149170    {
     
    151172
    152173        /**
    153         * Malicious guests may go beyond aSegsIn or aSegsOut boundaries by linking
     174        * Malicious guests may go beyond paSegsIn or paSegsOut boundaries by linking
    154175        * several descriptors into a loop. Since there is no legitimate way to get a sequences of
    155176        * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}),
    156177        * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
    157178        */
    158         if (pDescChain->cSegsIn + pDescChain->cSegsOut >= VIRTQ_MAX_SIZE)
     179        if (cSegsIn + cSegsOut >= VIRTQ_MAX_SIZE)
    159180        {
    160181            static volatile uint32_t s_cMessages  = 0;
     
    178199        {
    179200            Log6Func(("%s IN  desc_idx=%u seg=%u addr=%RGp cb=%u\n",
    180                 QUEUENAME(qIdx), uDescIdx, pDescChain->cSegsIn, desc.pGcPhysBuf, desc.cb));
     201                QUEUENAME(qIdx), uDescIdx, cSegsIn, desc.pGcPhysBuf, desc.cb));
    181202            cbIn += desc.cb;
    182             pSeg = &(pDescChain->aSegsIn[pDescChain->cSegsIn++]);
     203            pSeg = &(paSegsIn[cSegsIn++]);
    183204        }
    184205        else
    185206        {
    186207            Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n",
    187                 QUEUENAME(qIdx), uDescIdx, pDescChain->cSegsOut, desc.pGcPhysBuf, desc.cb));
     208                QUEUENAME(qIdx), uDescIdx, cSegsOut, desc.pGcPhysBuf, desc.cb));
    188209            cbOut += desc.cb;
    189             pSeg = &(pDescChain->aSegsOut[pDescChain->cSegsOut++]);
     210            pSeg = &(paSegsOut[cSegsOut++]);
    190211        }
    191212
     
    196217    } while (desc.fFlags & VIRTQ_DESC_F_NEXT);
    197218
    198     RTSgBufInit(&pVirtqProxy->inSgBuf,  (PCRTSGSEG)&pDescChain->aSegsIn,  pDescChain->cSegsIn);
    199     RTSgBufInit(&pVirtqProxy->outSgBuf, (PCRTSGSEG)&pDescChain->aSegsOut, pDescChain->cSegsOut);
    200 
    201     if (ppInSegs)
    202         *ppInSegs = &pVirtqProxy->inSgBuf;
    203 
    204     if (ppOutSegs)
    205         *ppOutSegs = &pVirtqProxy->outSgBuf;
     219
     220    PRTSGBUF pSgPhysIn = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF));
     221    AssertReturn(pSgPhysIn, VERR_NO_MEMORY);
     222
     223    RTSgBufInit(pSgPhysIn, (PCRTSGSEG)paSegsIn, cSegsIn);
     224
     225    void *pSgVirtOut = RTMemAlloc(cbOut);
     226    AssertReturn(pSgVirtOut, VERR_NO_MEMORY);
     227
     228    if (cSegsOut)
     229    {
     230        RTSGBUF outSgPhys;
     231        RTSgBufInit(&outSgPhys, (PCRTSGSEG)paSegsOut, cSegsOut);
     232        virtioSgPhysToVirt((PVIRTIOSTATE)hVirtio, &outSgPhys, pSgVirtOut, cbOut);
     233        RTMemFree(paSegsOut);
     234    }
     235
     236    PVIRTIO_DESC_CHAIN_T pDescChain = (PVIRTIO_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTIO_DESC_CHAIN_T));
     237    AssertReturn(pDescChain, VERR_NO_MEMORY);
     238
     239    pDescChain->uHeadIdx   = uHeadIdx;
     240    pDescChain->cbVirtSrc  = cbOut;
     241    pDescChain->pVirtSrc   = pSgVirtOut;
     242    pDescChain->cbPhysDst  = cbIn;
     243    pDescChain->pSgPhysDst = pSgPhysIn;
     244    *ppDescChain = pDescChain;
    206245
    207246    Log6Func(("%s -- segs OUT: %u (%u bytes)   IN: %u (%u bytes) --\n",
    208               pVirtqProxy->szVirtqName, pDescChain->cSegsOut, cbOut, pDescChain->cSegsIn, cbIn));
     247              pVirtq->szVirtqName, cSegsOut, cbOut, cSegsIn, cbIn));
    209248
    210249    return VINF_SUCCESS;
     
    212251
    213252 /** See API comments in header file prototype for description */
    214 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgBuf, bool fFence)
    215 {
    216 
    217     Assert(qIdx < sizeof(VIRTQ_PROXY_T));
     253int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgVirtReturn,
     254                   PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence)
     255{
     256    Assert(qIdx < VIRTQ_MAX_CNT);
    218257
    219258    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    220     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
    221     PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;
     259    PVIRTQSTATE  pVirtq = &pVirtio->virtqState[qIdx];
     260    PRTSGBUF pSgPhysReturn = pDescChain->pSgPhysDst;
    222261
    223262    AssertMsgReturn(DRIVER_OK(pVirtio) /*&& pVirtio->uQueueEnable[qIdx]*/,
    224263                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    225     /**
    226      * Copy caller's virtual memory sg buffer to physical memory
    227      */
    228     PRTSGBUF pBufSrc = pSgBuf;
    229     PRTSGBUF pBufDst = &pVirtqProxy->inSgBuf;
    230 
    231     size_t cbRemain = RTSgBufCalcTotalLength(pBufSrc);
     264
    232265    uint16_t uUsedIdx = virtioReadUsedRingIdx(pVirtio, qIdx);
    233266    Log6Func(("Copying client data to %s, desc chain (head desc_idx %d)\n",
    234267               QUEUENAME(qIdx), uUsedIdx));
    235268
     269    /*
     270     * Copy virtual memory s/g buffer containing data to return to the guest
     271     * to phys. memory described by (IN direction ) s/g buffer of the descriptor chain
     272     * original pulled from the queue, to 'send back' to the guest driver.
     273     */
     274    size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn);
     275    size_t cbCopy = 0;
    236276    while (cbRemain)
    237277    {
    238         uint64_t dstSgStart = (uint64_t)pBufDst->paSegs[pBufDst->idxSeg].pvSeg;
    239         uint64_t dstSgLen   = (uint64_t)pBufDst->paSegs[pBufDst->idxSeg].cbSeg;
    240         uint64_t dstSgCur   = (uint64_t)pBufDst->pvSegCur;
    241         size_t cbCopy = RT_MIN(pBufSrc->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart));
     278        PCRTSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg];
     279        uint64_t dstSgStart = (uint64_t)paSeg->pvSeg;
     280        uint64_t dstSgLen   = (uint64_t)paSeg->cbSeg;
     281        uint64_t dstSgCur   = (uint64_t)pSgPhysReturn->pvSegCur;
     282        cbCopy = RT_MIN(pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart));
    242283        PDMDevHlpPhysWrite(pVirtio->CTX_SUFF(pDevIns),
    243                           (RTGCPHYS)pBufDst->pvSegCur, pBufSrc->pvSegCur, cbCopy);
    244         RTSgBufAdvance(pBufSrc, cbCopy);
    245         RTSgBufAdvance(pBufDst, cbCopy);
     284                          (RTGCPHYS)pSgPhysReturn->pvSegCur, pSgVirtReturn->pvSegCur, cbCopy);
     285        RTSgBufAdvance(pSgVirtReturn, cbCopy);
     286        RTSgBufAdvance(pSgPhysReturn, cbCopy);
    246287        cbRemain -= cbCopy;
    247288    }
     289
    248290
    249291    if (fFence)
     
    252294    /** If this write-ahead crosses threshold where the driver wants to get an event flag it */
    253295    if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
    254         if (pVirtqProxy->uUsedIdx == virtioReadAvailUsedEvent(pVirtio, qIdx))
    255             pVirtqProxy->fEventThresholdReached = true;
     296        if (pVirtq->uUsedIdx == virtioReadAvailUsedEvent(pVirtio, qIdx))
     297            pVirtq->fEventThresholdReached = true;
    256298
    257299    /**
    258300     * Place used buffer's descriptor in used ring but don't update used ring's slot index.
    259301     * That will be done with a subsequent client call to virtioQueueSync() */
    260     virtioWriteUsedElem(pVirtio, qIdx,
    261                         pVirtqProxy->uUsedIdx++,
    262                         pDescChain->uHeadIdx,
    263                         pDescChain->cSegsIn);
     302    virtioWriteUsedElem(pVirtio, qIdx, pVirtq->uUsedIdx++, pDescChain->uHeadIdx, cbCopy);
     303
    264304
    265305    if (LogIs2Enabled())
    266306    {
    267         size_t cbInSgBuf = RTSgBufCalcTotalLength(pBufDst);
    268         size_t cbWritten = cbInSgBuf - RTSgBufCalcLengthLeft(pBufDst);
    269307        Log2Func((".... Copied %u bytes to %u byte buffer, residual=%d\n",
    270              cbWritten, cbInSgBuf, cbInSgBuf - cbWritten));
     308             cbCopy, pDescChain->cbPhysDst, pDescChain->cbPhysDst - cbCopy));
    271309    }
    272310    Log6Func(("Write ahead used_idx=%d, %s used_idx=%d\n",
    273          pVirtqProxy->uUsedIdx,  QUEUENAME(qIdx), uUsedIdx));
     311         pVirtq->uUsedIdx,  QUEUENAME(qIdx), uUsedIdx));
     312
     313    RTMemFree((void *)pSgPhysReturn->paSegs);
     314    RTMemFree(pSgPhysReturn);
     315    RTMemFree(pDescChain);
    274316
    275317    return VINF_SUCCESS;
     
    281323int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    282324{
    283     Assert(qIdx < sizeof(VIRTQ_PROXY_T));
     325    Assert(qIdx < sizeof(VIRTQSTATE));
    284326
    285327    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    286     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     328    PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx];
    287329
    288330    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     
    291333    uint16_t uIdx = virtioReadUsedRingIdx(pVirtio, qIdx);
    292334    Log6Func(("Updating %s used_idx from %u to %u\n",
    293               QUEUENAME(qIdx), uIdx, pVirtqProxy->uUsedIdx));
    294 
    295     virtioWriteUsedRingIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx);
     335              QUEUENAME(qIdx), uIdx, pVirtq->uUsedIdx));
     336
     337    virtioWriteUsedRingIdx(pVirtio, qIdx, pVirtq->uUsedIdx);
    296338    virtioNotifyGuestDriver(pVirtio, qIdx, false);
    297339
     
    306348    Assert(uNotifyIdx == qIdx);
    307349
    308     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
    309     Log6Func(("%s\n", pVirtqProxy->szVirtqName));
     350    PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx];
     351    Log6Func(("%s\n", pVirtq->szVirtqName));
    310352
    311353    /** Inform client */
     
    337379static void virtioNotifyGuestDriver(PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce)
    338380{
    339     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     381    PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx];
    340382
    341383    AssertMsgReturnVoid(DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"));
     
    345387        if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
    346388        {
    347             if (pVirtqProxy->fEventThresholdReached)
     389            if (pVirtq->fEventThresholdReached)
    348390            {
    349391                virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, fForce);
    350                 pVirtqProxy->fEventThresholdReached = false;
     392                pVirtq->fEventThresholdReached = false;
    351393                return;
    352394            }
     
    434476static void virtioResetQueue(PVIRTIOSTATE pVirtio, uint16_t qIdx)
    435477{
    436     PVIRTQ_PROXY_T pVirtQ = &pVirtio->virtqProxy[qIdx];
     478    PVIRTQSTATE pVirtQ = &pVirtio->virtqState[qIdx];
    437479    pVirtQ->uAvailIdx = 0;
    438480    pVirtQ->uUsedIdx  = 0;
     
    832874    Assert(cb >= 32);
    833875
    834     if (iRegion == VIRTIOSCSI_REGION_PCI_CAP)
     876    if (iRegion == VIRTIO_REGION_PCI_CAP)
    835877    {
    836878        /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
     
    885927        uint8_t  uBar    = pVirtio->pPciCfgCap->pciCap.uBar;
    886928        uint32_t pv = 0;
    887         if (uBar == VIRTIOSCSI_REGION_PCI_CAP)
     929        if (uBar == VIRTIO_REGION_PCI_CAP)
    888930            (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset),
    889931                                    &pv, uLength);
     
    929971        uint32_t uOffset = pVirtio->pPciCfgCap->pciCap.uOffset;
    930972        uint8_t  uBar    = pVirtio->pPciCfgCap->pciCap.uBar;
    931         if (uBar == VIRTIOSCSI_REGION_PCI_CAP)
     973        if (uBar == VIRTIO_REGION_PCI_CAP)
    932974            (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset),
    933975                                    (void *)&u32Value, uLength);
     
    11171159    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CAP_T);
    11181160    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    1119     pCfg->uBar     = VIRTIOSCSI_REGION_PCI_CAP;
     1161    pCfg->uBar     = VIRTIO_REGION_PCI_CAP;
    11201162    pCfg->uOffset  = RT_ALIGN_32(0, 4); /* reminder, in case someone changes offset */
    11211163    pCfg->uLength  = sizeof(VIRTIO_PCI_COMMON_CFG_T);
     
    11321174    pCfg->uCapLen  = sizeof(VIRTIO_PCI_NOTIFY_CAP_T);
    11331175    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    1134     pCfg->uBar     = VIRTIOSCSI_REGION_PCI_CAP;
     1176    pCfg->uBar     = VIRTIO_REGION_PCI_CAP;
    11351177    pCfg->uOffset  = pVirtio->pCommonCfgCap->uOffset + pVirtio->pCommonCfgCap->uLength;
    11361178    pCfg->uOffset  = RT_ALIGN_32(pCfg->uOffset, 2);
     
    11511193    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CAP_T);
    11521194    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    1153     pCfg->uBar     = VIRTIOSCSI_REGION_PCI_CAP;
     1195    pCfg->uBar     = VIRTIO_REGION_PCI_CAP;
    11541196    pCfg->uOffset  = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength;
    11551197    pCfg->uLength  = sizeof(uint8_t);
     
    11841226        pCfg->uCapLen  = sizeof(VIRTIO_PCI_CAP_T);
    11851227        pCfg->uCapNext = fMsiSupport ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
    1186         pCfg->uBar     = VIRTIOSCSI_REGION_PCI_CAP;
     1228        pCfg->uBar     = VIRTIO_REGION_PCI_CAP;
    11871229        pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
    11881230        pCfg->uOffset  = RT_ALIGN_32(pCfg->uOffset, 4);
     
    12141256     *  out size, so pad with an extra page */
    12151257
    1216     rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_PCI_CAP,  RT_ALIGN_32(cbRegion + 0x1000, 0x1000),
     1258    rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIO_REGION_PCI_CAP,  RT_ALIGN_32(cbRegion + 0x1000, 0x1000),
    12171259                                      PCI_ADDRESS_SPACE_MEM, virtioR3Map);
    12181260    if (RT_FAILURE(rc))
     
    12661308    {
    12671309        Log2Func(("%s queue:\n",
    1268                   "  virtqProxy[%u].uAvailIdx    = %u\n  virtqProxy[%u].uUsedIdx    = %u\n"
     1310                  "  virtqState[%u].uAvailIdx    = %u\n  virtqState[%u].uUsedIdx    = %u\n"
    12691311                  "  uQueueSize[%u]              = %u\n  uQueueNotifyOff[%u]         = %04x\n"
    12701312                  "  uQueueMsixVector[%u]        = %04x\n  uQueueEnable[%u]            = %04x\n"
    12711313                  "  pGcPhysQueueDesc[%u]        = %RGp\n  pGcPhysQueueAvail[%u]       = %RGp\n"
    12721314                  "  pGcPhysQueueUsed[%u]        = %RGp\n",
    1273                         i, pVirtio->virtqProxy[i].szVirtqName, i, pVirtio->virtqProxy[i].uAvailIdx,
    1274                         i, pVirtio->virtqProxy[i].uUsedIdx, i, pVirtio->uQueueSize[i],
     1315                        i, pVirtio->virtqState[i].szVirtqName, i, pVirtio->virtqState[i].uAvailIdx,
     1316                        i, pVirtio->virtqState[i].uUsedIdx, i, pVirtio->uQueueSize[i],
    12751317                        i, pVirtio->uQueueNotifyOff[i],i, pVirtio->uQueueMsixVector[i],
    12761318                        i, pVirtio->uQueueEnable[i], i, pVirtio->pGcPhysQueueDesc[i],
     
    13301372        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueEnable[i]);
    13311373        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueSize[i]);
    1332         rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uAvailIdx);
    1333         rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uUsedIdx);
    1334         rc = SSMR3PutMem(pSSM,      pVirtio->virtqProxy[i].szVirtqName, 32);
     1374        rc = SSMR3PutU16(pSSM,      pVirtio->virtqState[i].uAvailIdx);
     1375        rc = SSMR3PutU16(pSSM,      pVirtio->virtqState[i].uUsedIdx);
     1376        rc = SSMR3PutMem(pSSM,      pVirtio->virtqState[i].szVirtqName, 32);
    13351377    }
    13361378
     
    13891431            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueEnable[i]);
    13901432            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueSize[i]);
    1391             rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uAvailIdx);
    1392             rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uUsedIdx);
    1393             rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqProxy[i].szVirtqName, 32);
     1433            rc = SSMR3GetU16(pSSM,      &pVirtio->virtqState[i].uAvailIdx);
     1434            rc = SSMR3GetU16(pSSM,      &pVirtio->virtqState[i].uUsedIdx);
     1435            rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqState[i].szVirtqName, 32);
    13941436        }
    13951437    }
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r80683 r80762  
    3838#define VIRTQ_MAX_CNT                       24                   /**< Max queues we allow guest to create      */
    3939#define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
    40 #define VIRTIOSCSI_REGION_MEM_IO            0                    /**< BAR for MMIO (implementation specific)   */
    41 #define VIRTIOSCSI_REGION_PORT_IO           1                    /**< BAR for PORT I/O (impl specific)         */
    42 #define VIRTIOSCSI_REGION_PCI_CAP           2                    /**< BAR for VirtIO Cap. MMIO (impl specific) */
     40#define VIRTIO_REGION_PCI_CAP               2                    /**< BAR for VirtIO Cap. MMIO (impl specific) */
    4341
    4442#define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \
     
    4745            virtioHexDump((pv), (cb), (base), (title)); \
    4846    } while (0)
     47
     48
     49/**
     50 * The following structure holds the pre-processed context of descriptor chain pulled from a virtio queue
     51 * to conduct a transaction between the client of this virtio implementation and the guest VM's virtio driver.
     52 * It contains the head index of the descriptor chain, the output data from the client that has been
     53 * converted to a contiguous virtual memory and a physical memory scatter-gather buffer for use by by
     54 * the virtio framework to complete the transaction in the final phase of round-trip processing.
     55 *
     56 * The client should not modify the contents of this buffer. The primary field of interest to the
     57 * client is pVirtSrc, which contains the VirtIO "OUT" (to device) buffer from the guest.
     58 *
     59 * Typical use is, When the client (worker thread) detects available data on the queue, it pulls the
     60 * next one of these descriptor chain structs off the queue using virtioQueueGet(), processes the
     61 * virtual memory buffer pVirtSrc, produces result data to pass back to the guest driver and calls
     62 * virtioQueuePut() to return the result data to the client.
     63 */
     64typedef struct VIRTIO_DESC_CHAIN
     65{
     66    uint32_t  uHeadIdx;                                    /**< Head idx of associated desc chain        */
     67    size_t    cbVirtSrc;                                   /**< Size of virt source buffer               */
     68    void     *pVirtSrc;                                    /**< Virt mem buf holding out data from guest */
     69    size_t    cbPhysDst;                                   /**< Total size of dst buffer                 */
     70    PRTSGBUF  pSgPhysDst;                                  /**< Phys S/G buf to store result for guest   */
     71} VIRTIO_DESC_CHAIN_T, *PVIRTIO_DESC_CHAIN_T, **PPVIRTIO_DESC_CHAIN_T;
    4972
    5073/**
     
    155178int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName);
    156179
    157 
    158 /**
    159  * Get the features VirtIO is running withnow.
    160  *
    161  * @returns Features the guest driver has accepted, finalizing the operational features
    162  *
    163  */
    164 uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio);
    165 
    166180/**
    167181 * Detaches from queue and release resources
     
    174188
    175189/**
    176  * Get name of queue, by qIdx, assigned at virtioQueueAttach()
    177  *
    178  * @param hVirtio   - Handle for VirtIO framework
    179  * @param qIdx      - Queue number
    180  *
    181  * @returns          Success: Returns pointer to queue name
    182  *                   Failure: Returns "<null>" (never returns NULL pointer).
    183  */
    184 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx);
    185 
    186 /**
    187  * Removes descriptor chain from avail ring of indicated queue and converts it to
    188  * scatter/gather buffer (whose segments contain guest phys. data pointers)
    189  *
    190  * @param hVirtio   - Handle for VirtIO framework
    191  * @param qIdx      - Queue number
    192  * @param ppInSegs  - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
    193  * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
    194  *
    195  * @returns status    VINF_SUCCESS         - Success
    196  *                    VERR_INVALID_STATE   - VirtIO not in ready state
    197  */
    198 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs);
    199 
    200 /**
    201  * Same as virtioQueueGet() but leaves the item on the avail ring of the queue.
    202  *
    203  * @param hVirtio   - Handle for VirtIO framework
    204  * @param qIdx      - Queue number
    205  * @param ppInSegs  - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
    206  * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
    207  *
    208  * @returns           VINF_SUCCESS         - Success
    209  *                    VERR_INVALID_STATE   - VirtIO not in ready state
    210  *                    VERR_NOT_AVAILABLE   - Queue is empty
    211  */
    212 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs);
    213 
    214 /**
    215  * Writes a scatter/gather buffer (whose segments point to virtual memory) to next
    216  * available descriptor chain (consisting of segments pointing to guest phys. memory),
    217  * for the indicated virtq. The data won't be seen by the guest until the next
    218  * client call to virtioQueueSync(), which puts aforementioned descriptor
    219  * chain's head index on the indicated virtq's used ring (see VirtIO 1.0
    220  * specification, Section 2.4 "Virtqueues").
    221  *
    222  * @param hVirtio   - Handle for VirtIO framework
    223  * @param qIdx      - Queue number
    224  * @param pSgBuf    - Caller's sgbuf of one or more virtual memory segments
    225  *                    to write to the queue. This is useful because some kinds
    226  *                    of transactions involve variable length subcomponents
    227  *                    whose size can only be known near the time of writing.
    228  * @parame fFence   - If set put up copy fence (memory barrier) after
    229  *                    copying to guest phys. mem.
    230  *
    231  * @returns           VINF_SUCCESS         - Success
    232  *                    VERR_INVALID_STATE   - VirtIO not in ready state
    233  *                    VERR_NOT_AVAILABLE   - Queue is empty
    234  */
    235 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgBuf, bool fFence);
     190 * Removes descriptor chain from avail ring of indicated queue and converts the descriptor
     191 * chain into its OUT (to device) and IN to guest components. Additionally it converts
     192 * the OUT desc chain data to a contiguous virtual memory buffer for easy consumption
     193 * by the caller. The caller must return the descriptor chain pointer via virtioQueuePut()
     194 * and then call virtioQueueSync() at some point to return the data to the guest and
     195 * complete the transaction.
     196 *
     197 * @param hVirtio      - Handle for VirtIO framework
     198 * @param qIdx         - Queue number
     199 * @param fRemove      - flags whether to remove desc chain from queue (false = peek)
     200 * @param ppDescChain  - Address to store pointer to descriptor chain that contains the
     201 *                       pre-processed transaction information pulled from the virtq.
     202 *
     203 * @returns status     VINF_SUCCESS         - Success
     204 *                     VERR_INVALID_STATE   - VirtIO not in ready state
     205 */
     206int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove);
     207
     208
     209/**
     210 * Returns data to the guest to complete a transaction initiated by virtQueueGet().
     211 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments
     212 * and a pointer to the descriptor chain context originally derived from the pulled
     213 * queue entry, and this function will put write the virtual memory s/g buffer into the
     214 * guest's physical memory free the descriptor chain. The caller handles the freeing
     215 * (as needed) of the virtual memory buffer.
     216 *
     217 * NOTE: This does a write-ahead to the used ring of the guest's queue.
     218 *       The data written won't be seen by the guest until the next call to virtioQueueSync()
     219 *
     220 *
     221 * @param hVirtio       - Handle for VirtIO framework
     222 * @param qIdx          - Queue number
     223 *
     224 * @param pSgVirtReturn - Points toscatter-gather buffer of virtual memory segments
     225                          the caller is returning to the guest.
     226 *
     227 * @param pDescChain    - This contains the context of the scatter-gather buffer
     228 *                        originally pulled from the queue.
     229 *
     230 * @parame fFence       - If true, put up copy fence (memory barrier) after
     231 *                        copying to guest phys. mem.
     232 *
     233 * @returns              VINF_SUCCESS         - Success
     234 *                       VERR_INVALID_STATE   - VirtIO not in ready state
     235 *                       VERR_NOT_AVAILABLE   - Queue is empty
     236 */
     237
     238 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgVirtReturn,
     239                    PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence);
     240
    236241
    237242/**
     
    297302void virtioPropagateResumeNotification(VIRTIOHANDLE hVirtio);
    298303
     304/**
     305 * Get name of queue, by qIdx, assigned at virtioQueueAttach()
     306 *
     307 * @param hVirtio   - Handle for VirtIO framework
     308 * @param qIdx      - Queue number
     309 *
     310 * @returns          Success: Returns pointer to queue name
     311 *                   Failure: Returns "<null>" (never returns NULL pointer).
     312 */
     313const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     314
     315/**
     316 * Get the features VirtIO is running withnow.
     317 *
     318 * @returns Features the guest driver has accepted, finalizing the operational features
     319 *
     320 */
     321uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio);
    299322
    300323
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r80718 r80762  
    8585
    8686/**
    87  * IN/OUT Descriptor chains descriptor chain associated with one element of virtq avail ring represented
    88  * as respective arrays of SG segments.
    89  */
    90 typedef struct VIRTQ_DESC_CHAIN                                  /**< Describes a single queue element          */
    91 {
    92     RTSGSEG     aSegsIn[VIRTQ_MAX_SIZE];                         /**< List of segments to write to guest        */
    93     RTSGSEG     aSegsOut[VIRTQ_MAX_SIZE];                        /**< List of segments read from guest          */
    94     uint32_t    uHeadIdx;                                        /**< Index at head desc (source of seg arrays) */
    95     uint32_t    cSegsIn;                                         /**< Count of segments in aSegsIn[]            */
    96     uint32_t    cSegsOut;                                        /**< Count of segments in aSegsOut[]           */
    97 } VIRTQ_DESC_CHAIN_T, *PVIRTQ_DESC_CHAIN_T;
    98 
    99 /**
    10087 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification)
    10188 */
    102 typedef struct VIRTQ_PROXY
    103 {
    104     RTSGBUF     inSgBuf;                                         /**< host-to-guest buffers                     */
    105     RTSGBUF     outSgBuf;                                        /**< guest-to-host buffers                     */
     89typedef struct VIRTQSTATE
     90{
    10691    const char  szVirtqName[32];                                 /**< Dev-specific name of queue                */
    10792    uint16_t    uAvailIdx;                                       /**< Consumer's position in avail ring         */
    10893    uint16_t    uUsedIdx;                                        /**< Consumer's position in used ring          */
    10994    bool        fEventThresholdReached;                          /**< Don't lose track while queueing ahead     */
    110     PVIRTQ_DESC_CHAIN_T pDescChain;                              /**< Per-queue s/g data.                       */
    111 } VIRTQ_PROXY_T, *PVIRTQ_PROXY_T;
     95} VIRTQSTATE, *PVIRTQSTATE;
    11296
    11397/**
     
    191175    uint8_t                   uConfigGeneration;                 /**< (MMIO) Device config sequencer       HOST */
    192176
    193     VIRTQ_PROXY_T             virtqProxy[VIRTQ_MAX_CNT];         /**< Local impl-specific queue context         */
     177    VIRTQSTATE                virtqState[VIRTQ_MAX_CNT];         /**< Local impl-specific queue context         */
    194178    VIRTIOCALLBACKS           virtioCallbacks;                   /**< Callback vectors to client                */
    195179
     
    378362DECLINLINE(bool) virtqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx)
    379363{
    380     return virtioReadAvailRingIdx(pVirtio, qIdx) == pVirtio->virtqProxy[qIdx].uAvailIdx;
     364    return virtioReadAvailRingIdx(pVirtio, qIdx) == pVirtio->virtqState[qIdx].uAvailIdx;
    381365}
    382366
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