VirtualBox

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


Ignore:
Timestamp:
Aug 12, 2019 7:23:05 AM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
132668
Message:

storage/DevVirtioSCSI.cpp, major changes that flesh out most of the functionality of the VirtIO 1.0 implementation (not the Host SCSI dev specific implmentation). See #9440, Comment #45 for more information

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

Legend:

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

    r80201 r80219  
    2727#include <iprt/uuid.h>
    2828#include <iprt/mem.h>
     29#include <iprt/assert.h>
    2930#include <VBox/vmm/pdmdev.h>
    3031#include "Virtio_1_0_impl.h"
    3132#include "Virtio_1_0.h"
    3233
    33 #define INSTANCE(pState) pState->szInstance
    34 #define IFACE_TO_STATE(pIface, ifaceName) ((VIRTIOSTATE *)((char*)(pIface) - RT_UOFFSETOF(VIRTIOSTATE, ifaceName)))
    35 
    36 #define H2P(hVirtio) ((PVIRTIOSTATE)(hVirtio))
     34#define INSTANCE(pVirtio) pVirtio->szInstance
    3735
    3836#ifdef LOG_ENABLED
     
    4341 * Formats the logging of a memory-mapped I/O input or output value
    4442 *
    45  * @param   pszFunc     - To avoid displaying this function's name via __FUNCTION__ or LogFunc()
     43 * @param   pszFunc     - To avoid displaying this function's name via __FUNCTION__ or Log2Func()
    4644 * @param   pszMember   - Name of struct member
    4745 * @param   pv          - pointer to value
     
    5250 * @param   idx         - The index if fHasIndex
    5351 */
    54 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, const void *pv, uint32_t cb,
    55                         uint32_t uOffset, bool fWrite, bool fHasIndex, uint32_t idx)
    56 {
    57 
    58 #define FMTHEX(fmtout, val, cNybs) \
    59     fmtout[cNybs] = '\0'; \
    60     for (uint8_t i = 0; i < cNybs; i++) \
    61         fmtout[(cNybs - i) -1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf];
     52void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, size_t uMemberSize,
     53                        const void *pv, uint32_t cb, uint32_t uOffset, bool fWrite,
     54                        bool fHasIndex, uint32_t idx)
     55{
     56
     57#define FMTHEX(fmtout, val, cNybbles) \
     58    fmtout[cNybbles] = '\0'; \
     59    for (uint8_t i = 0; i < cNybbles; i++) \
     60        fmtout[(cNybbles - i) - 1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf];
    6261
    6362#define MAX_STRING   64
     
    7372        memcpy((char *)&val, pv, cb);
    7473        FMTHEX(pszFormattedVal, val, cb * 2);
    75         if (uOffset != 0) /* display bounds if partial member access */
     74        if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */
    7675            RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]",
    7776                        pszMember, pszIdx, uOffset, uOffset + cb - 1);
     
    8180        uint32_t first = 0;
    8281        for (uint8_t i = 0; i < sizeof(pszDepiction); i++)
    83             if (pszDepiction[i] == ' ' && first++ != 0)
     82            if (pszDepiction[i] == ' ' && first++)
    8483                pszDepiction[i] = '.';
    8584        Log(("%s: Guest %s %s 0x%s\n", \
     
    9493}
    9594
    96 
    97 void virtQueueReadDesc(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx, PVIRTQ_DESC_T pDesc)
    98 {
    99     //Log(("%s virtQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx));
    100     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    101                       pVirtQ->pGcPhysVirtqDescriptors + sizeof(VIRTQ_DESC_T) * (idx % pVirtQ->cbQueue),
    102                       pDesc, sizeof(VIRTQ_DESC_T));
    103 }
    104 
    105 uint16_t virtQueueReadAvail(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx)
    106 {
    107     uint16_t tmp;
    108     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    109                       pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[idx % pVirtQ->cbQueue]),
    110                       &tmp, sizeof(tmp));
    111     return tmp;
    112 }
    113 
    114 uint16_t virtQueueReadAvailFlags(PVIRTIOSTATE pState, PVIRTQ pVirtQ)
    115 {
    116     uint16_t tmp;
    117     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    118                       pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
    119                       &tmp, sizeof(tmp));
    120     return tmp;
    121 }
    122 
    123 uint16_t virtQueueReadUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ)
    124 {
    125     uint16_t tmp;
    126     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    127                       pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    128                       &tmp, sizeof(tmp));
    129     return tmp;
    130 }
    131 
    132 void virtQueueWriteUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint16_t u16Value)
    133 {
    134     PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    135                           pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    136                           &u16Value, sizeof(u16Value));
    137 }
    138 
    139 void virtQueueWriteUsedElem(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx, uint32_t id, uint32_t uLen)
    140 {
    141 
    142     RT_NOREF5(pState, pVirtQ, idx, id, uLen);
    143     /* PK TODO: Adapt to VirtIO 1.0
    144     VIRTQ_USED_ELEM_T elem;
    145 
    146     elem.id = id;
    147     elem.uLen = uLen;
    148     PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    149                           pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF_DYN(VIRTQ_USED_T, ring[idx % pVirtQ->cbQueue]),
    150                           &elem, sizeof(elem));
    151     */
    152 }
    153 
    154 void virtQueueSetNotification(PVIRTIOSTATE pState, PVIRTQ pVirtQ, bool fEnabled)
    155 {
    156     RT_NOREF3(pState, pVirtQ, fEnabled);
    157 
    158 /* PK TODO: Adapt to VirtIO 1.0
    159     uint16_t tmp;
    160 
    161     PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
    162                       pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags),
    163                       &tmp, sizeof(tmp));
    164 
    165     if (fEnabled)
    166         tmp &= ~ VIRTQ_USED_T_F_NO_NOTIFY;
    167     else
    168         tmp |= VIRTQ_USED_T_F_NO_NOTIFY;
    169 
    170     PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    171                           pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags),
    172                           &tmp, sizeof(tmp));
    173 */
    174 }
    175 
    176 bool virtQueueSkip(PVIRTIOSTATE pState, PVQUEUE pQueue)
    177 {
    178 
    179     RT_NOREF2(pState, pQueue);
    180 /* PK TODO Adapt to VirtIO 1.0
    181     if (virtQueueIsEmpty(pState, pQueue))
     95/**
     96 * This is called when MMIO handler detects guest write to a virtq's notification address
     97 */
     98static void vqNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx)
     99{
     100    Assert(uNotifyIdx == qIdx);
     101    PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx];
     102    Log2Func(("%s: %s notified\n", INSTANCE(pVirtio), pQueueContext->pcszName));
     103
     104    /** inform client */
     105    pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, qIdx);
     106}
     107
     108static void vqNotify(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     109{
     110    PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx];
     111
     112    bool fEmpty = vqIsEmpty(pVirtio, qIdx);
     113    bool fAvailFlags = vqReadAvailFlags(pVirtio, qIdx);
     114
     115    LogFlowFunc(("%s: %s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n",
     116        INSTANCE(pVirtio), pQueueContext->pcszName, fAvailFlags, pVirtio->uDriverFeatures, fEmpty ? "" : "not "));
     117
     118    if (!(fAvailFlags & VIRTQ_AVAIL_F_NO_INTERRUPT))
     119    {
     120        int rc = virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT);
     121        if (RT_FAILURE(rc))
     122            Log(("%s virtioQueueNotify: Failed to raise an interrupt (%Rrc).\n", INSTANCE(pVirtio), rc));
     123    }
     124}
     125
     126bool virtioQueueInit(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName)
     127{
     128    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     129    PVIRTQ_CONTEXT_T pVirtQ = &(pVirtio->queueContext[qIdx]);
     130    if (pVirtio->uQueueEnable[qIdx])
     131    {
     132        Log2Func(("Queue name: %-16s\n", pcszName));
     133        pVirtQ->uNextAvailIdx = 0;
     134        pVirtQ->uNextUsedIdx  = 0;
     135        RTStrCopy((char *)pVirtQ->pcszName, sizeof(pVirtQ->pcszName), pcszName);
     136        return true;
     137    }
     138    return false;
     139}
     140
     141const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     142{
     143    return (const char *)((PVIRTIOSTATE)hVirtio)->queueContext[qIdx].pcszName;
     144}
     145
     146int virtioGetNumQueues(VIRTIOHANDLE hVirtio)
     147{
     148    return ((PVIRTIOSTATE)(hVirtio))->uNumQueues;
     149}
     150
     151bool virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     152{
     153    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     154    PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx];
     155
     156    if (virtioQueueIsEmpty(pVirtio, qIdx))
    182157        return false;
    183158
    184     Log2(("%s virtQueueSkip: %s avail_idx=%u\n", INSTANCE(pState),
    185           QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex));
    186     pQueue->uNextAvailIndex++;
    187 */
     159    Log2Func(("%s: %s avail_idx=%u\n", INSTANCE(pVirtio),
     160          pQueueContext->pcszName, pQueueContext->uNextAvailIdx));
     161    pQueueContext->uNextAvailIdx++;
    188162    return true;
    189163}
    190164
    191 bool virtQueueGet(PVIRTIOSTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove)
    192 {
    193 
    194     RT_NOREF4(pState, pQueue, pElem, fRemove);
    195 
    196 /* PK TODO: Adapt to VirtIO 1.0
    197     if (virtQueueIsEmpty(pState, pQueue))
     165bool virtioQueueIsEmpty(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     166{
     167    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     168    return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->queueContext->uNextAvailIdx;
     169}
     170
     171bool virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec)
     172{
     173    return virtioQueueGet(hVirtio, qIdx, pBufVec, /* fRemove */ false);
     174}
     175
     176bool virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, bool fRemove)
     177{
     178
     179    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     180    PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx];
     181
     182    if (vqIsEmpty(pVirtio, qIdx))
    198183        return false;
    199184
    200     pElem->nIn = pElem->nOut = 0;
    201 
    202     Log2(("%s virtQueueGet: %s avail_idx=%u\n", INSTANCE(pState),
    203           QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex));
     185    pBufVec->cSegsIn = pBufVec->cSegsOut = 0;
     186
     187    Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pQueueContext->pcszName, pQueueContext->uNextAvailIdx));
     188
     189    uint16_t uDescIdx;
     190    pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pQueueContext->uNextAvailIdx);
     191
     192    if (fRemove)
     193        pQueueContext->uNextAvailIdx++;
    204194
    205195    VIRTQ_DESC_T desc;
    206     uint16_t  idx = virtQueueReadAvail(pState, &pQueue->VirtQ, pQueue->uNextAvailIndex);
    207     if (fRemove)
    208         pQueue->uNextAvailIndex++;
    209     pElem->idx = idx;
    210196    do
    211197    {
    212         VQUEUESEG *pSeg;
    213 
    214         //
    215         // Malicious guests may try to trick us into writing beyond aSegsIn or
    216         // aSegsOut boundaries by linking several descriptors into a loop. We
    217         // cannot possibly get a sequence of linked descriptors exceeding the
    218         // total number of descriptors in the ring (see @bugref{8620}).
    219         ///
    220         if (pElem->nIn + pElem->nOut >= VIRTQ_MAX_SIZE)
     198        VIRTQ_SEG_T *pSeg;
     199
     200        /**
     201        * Malicious or inept guests may go beyond aSegsIn or aSegsOut boundaries by linking
     202        * several descriptors into a loop. Since there is no legitimate way to get a sequences of
     203        * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}),
     204        * the following aborts I/O if breech and employs a simple log throttling algorithm to notify.
     205        */
     206        if (pBufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE)
    221207        {
    222208            static volatile uint32_t s_cMessages  = 0;
     
    224210            if (ASMAtomicIncU32(&s_cMessages) == ASMAtomicReadU32(&s_cThreshold))
    225211            {
    226                 LogRel(("%s: too many linked descriptors; check if the guest arranges descriptors in a loop.\n",
    227                         INSTANCE(pState)));
     212                LogRel(("%s: too many linked descriptors; "
     213                        "check if the guest arranges descriptors in a loop.\n",
     214                           INSTANCE(pVirtio)));
    228215                if (ASMAtomicReadU32(&s_cMessages) != 1)
    229216                    LogRel(("%s: (the above error has occured %u times so far)\n",
    230                             INSTANCE(pState), ASMAtomicReadU32(&s_cMessages)));
     217                            INSTANCE(pVirtio), ASMAtomicReadU32(&s_cMessages)));
    231218                ASMAtomicWriteU32(&s_cThreshold, ASMAtomicReadU32(&s_cThreshold) * 10);
    232219            }
     
    235222        RT_UNTRUSTED_VALIDATED_FENCE();
    236223
    237         virtQueueReadDesc(pState, &pQueue->VirtQ, idx, &desc);
    238         if (desc.u16Flags & VIRTQ_DESC_T_F_WRITE)
    239         {
    240             Log2(("%s virtQueueGet: %s IN  seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),
    241                   QUEUENAME(pState, pQueue), pElem->nIn, idx, desc.addr, desc.uLen));
    242             pSeg = &pElem->aSegsIn[pElem->nIn++];
     224        vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
     225        if (desc.fFlags & VIRTQ_DESC_F_WRITE)
     226        {
     227            Log2Func(("%s: %s IN  seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),
     228                  pQueueContext->pcszName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb));
     229            pSeg = &(pBufVec->aSegsIn[pBufVec->cSegsIn++]);
    243230        }
    244231        else
    245232        {
    246             Log2(("%s virtQueueGet: %s OUT seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),
    247                   QUEUENAME(pState, pQueue), pElem->nOut, idx, desc.addr, desc.uLen));
    248             pSeg = &pElem->aSegsOut[pElem->nOut++];
    249         }
    250 
    251         pSeg->addr = desc.addr;
    252         pSeg->cb   = desc.uLen;
     233            Log2Func(("%s: %s IN  seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),
     234                  pQueueContext->pcszName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb));
     235            pSeg = &(pBufVec->aSegsOut[pBufVec->cSegsOut++]);
     236        }
     237
     238        pSeg->addr = (RTGCPHYS)desc.pGcPhysBuf;
     239        pSeg->cb   = desc.cb;
    253240        pSeg->pv   = NULL;
    254241
    255         idx = desc.next;
    256     } while (desc.u16Flags & VIRTQ_DESC_T_F_NEXT);
    257 
    258     Log2(("%s virtQueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState),
    259           QUEUENAME(pState, pQueue), pElem->idx, pElem->nIn, pElem->nOut));
    260 */
     242        uDescIdx = desc.uDescIdxNext;
     243    } while (desc.fFlags & VIRTQ_DESC_F_NEXT);
     244
     245    Log2Func(("%s: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pVirtio),
     246          pQueueContext->pcszName, pBufVec->uDescIdx, pBufVec->cSegsIn, pBufVec->cSegsOut));
     247
    261248    return true;
    262249}
    263250
    264 
    265 
    266 void virtQueuePut(PVIRTIOSTATE pState, PVQUEUE pQueue,
    267                PVQUEUEELEM pElem, uint32_t uTotalLen, uint32_t uReserved)
    268 {
    269 
    270     RT_NOREF5(pState, pQueue, pElem, uTotalLen, uReserved);
    271 
    272 /* PK TODO Re-work this for VirtIO 1.0
    273     Log2(("%s virtQueuePut: %s"
    274           " desc_idx=%u acb=%u (%u)\n",
    275           INSTANCE(pState), QUEUENAME(pState, pQueue),
    276           pElem->idx, uTotalLen, uReserved));
    277 
    278     Assert(uReserved < uTotalLen);
    279 
    280     uint32_t cbLen = uTotalLen - uReserved;
    281     uint32_t cbSkip = uReserved;
    282 
    283     for (unsigned i = 0; i < pElem->nIn && cbLen > 0; ++i)
    284     {
    285         if (cbSkip >= pElem->aSegsIn[i].cb) // segment completely skipped?
    286         {
    287             cbSkip -= pElem->aSegsIn[i].cb;
    288             continue;
    289         }
    290 
    291         uint32_t cbSegLen = pElem->aSegsIn[i].cb - cbSkip;
    292         if (cbSegLen > cbLen)   // last segment only partially used?
    293             cbSegLen = cbLen;
    294 
    295         //
    296         // XXX: We should assert pv != NULL, but we need to check and
    297         // fix all callers first.
    298         //
    299         if (pElem->aSegsIn[i].pv != NULL)
    300         {
    301             Log2(("%s virtQueuePut: %s"
    302                   " used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n",
    303                   INSTANCE(pState), QUEUENAME(pState, pQueue),
    304                   pQueue->uNextUsedIndex, i,
    305                   (void *)pElem->aSegsIn[i].addr, pElem->aSegsIn[i].pv,
    306                   pElem->aSegsIn[i].cb, cbSegLen));
    307 
    308             PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns),
    309                                   pElem->aSegsIn[i].addr + cbSkip,
    310                                   pElem->aSegsIn[i].pv,
    311                                   cbSegLen);
    312         }
    313 
    314         cbSkip = 0;
    315         cbLen -= cbSegLen;
    316     }
    317 
    318     Log2(("%s virtQueuePut: %s"
    319           " used_idx=%u guest_used_idx=%u id=%u len=%u\n",
    320           INSTANCE(pState), QUEUENAME(pState, pQueue),
    321           pQueue->uNextUsedIndex, virtQueueReadUsedIndex(pState, &pQueue->VirtQ),
    322           pElem->idx, uTotalLen));
    323 
    324     virtQueueWriteUsedElem(pState, &pQueue->VirtQ,
    325                        pQueue->uNextUsedIndex++,
    326                        pElem->idx, uTotalLen);
    327 */
    328 
    329 }
    330 
    331 
    332 void virtQueueNotify(PVIRTIOSTATE pState, PVQUEUE pQueue)
    333 {
    334 
    335     RT_NOREF2(pState, pQueue);
    336 /* PK TODO Adapt to VirtIO 1.0
    337     LogFlow(("%s virtQueueNotify: %s availFlags=%x guestFeatures=%x virtQueue is %sempty\n",
    338              INSTANCE(pState), QUEUENAME(pState, pQueue),
    339              virtQueueReadAvailFlags(pState, &pQueue->VirtQ),
    340              pState->uGuestFeatures, virtQueueIsEmpty(pState, pQueue)?"":"not "));
    341     if (!(virtQueueReadAvailFlags(pState, &pQueue->VirtQ) & VIRTQ_AVAIL_T_F_NO_INTERRUPT)
    342         || ((pState->uGuestFeatures & VIRTIO_F_NOTIFY_ON_EMPTY) && virtQueueIsEmpty(pState, pQueue)))
    343     {
    344         int rc = virtioRaiseInterrupt(pState, VERR_INTERNAL_ERROR, VIRTIO_ISR_QUEUE);
    345         if (RT_FAILURE(rc))
    346             Log(("%s virtQueueNotify: Failed to raise an interrupt (%Rrc).\n", INSTANCE(pState), rc));
    347     }
    348 */
    349 }
    350 
    351 void virtQueueSync(PVIRTIOSTATE pState, PVQUEUE pQueue)
    352 {
    353     RT_NOREF(pState, pQueue);
    354 /* PK TODO Adapt to VirtIO 1.0
    355     Log2(("%s virtQueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState),
    356           QUEUENAME(pState, pQueue), virtQueueReadUsedIndex(pState, &pQueue->VirtQ), pQueue->uNextUsedIndex));
    357     virtQueueWriteUsedIndex(pState, &pQueue->VirtQ, pQueue->uNextUsedIndex);
    358     virtQueueNotify(pState, pQueue);
    359 */
    360 }
    361 
    362 
    363 
    364 /**
    365  * Raise interrupt.
    366  *
    367  * @param   pState      The device state structure.
    368  * @param   rcBusy      Status code to return when the critical section is busy.
    369  * @param   u8IntCause  Interrupt cause bit mask to set in PCI ISR port.
    370  */
    371 __attribute__((unused))
    372 int virtioRaiseInterrupt(VIRTIOSTATE *pState, int rcBusy, uint8_t u8IntCause)
    373 {
    374     RT_NOREF2(pState, u8IntCause);
    375     RT_NOREF_PV(rcBusy);
    376     LogFlow(("%s virtioRaiseInterrupt: u8IntCause=%x\n",
    377              INSTANCE(pState), u8IntCause));
    378 
    379     pState->uISR |= u8IntCause;
    380     PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 1);
    381     return VINF_SUCCESS;
    382 }
    383 
    384 /**
    385  * Lower interrupt.
    386  *
    387  * @param   pState      The device state structure.
    388  */
    389 __attribute__((unused))
    390 static void virtioLowerInterrupt(VIRTIOSTATE *pState)
    391 {
    392     LogFlow(("%s virtioLowerInterrupt\n", INSTANCE(pState)));
    393     PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 0);
    394 }
    395 
    396 
    397 #ifdef IN_RING3
    398 /**
    399  * Saves the state of device.
    400  *
    401  * @returns VBox status code.
    402  * @param   pDevIns     The device instance.
    403  * @param   pSSM        The handle to the saved state.
    404  */
    405 int virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM)
    406 {
    407     int rc = VINF_SUCCESS;
    408     virtioDumpState(pVirtio, "virtioSaveExec");
    409     RT_NOREF(pSSM);
    410     /*
    411      * PK TODO save guest features, queue selector, sttus ISR,
    412      *              and per queue info (size, address, indicies)...
    413      * using calls like SSMR3PutU8(), SSMR3PutU16(), SSMR3PutU16()...
    414      * and AssertRCReturn(rc, rc)
    415      */
    416 
    417     return rc;
    418 }
    419 
    420 /**
    421  * Loads a saved device state.
    422  *
    423  * @returns VBox status code.
    424  * @param   pDevIns     The device instance.
    425  * @param   pSSM        The handle to the saved state.
    426  * @param   uVersion    The data unit version number.
    427  * @param   uPass       The data pass.
    428  */
    429 int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t uNumQueues)
    430 {
    431     RT_NOREF5(pVirtio, pSSM, uVersion, uPass, uNumQueues);
    432     int rc = VINF_SUCCESS;
    433     virtioDumpState(pVirtio, "virtioLoadExec");
    434 
    435     /*
    436      * PK TODO, restore everything saved in virtioSaveExect, using
    437      * using calls like SSMR3PutU8(), SSMR3PutU16(), SSMR3PutU16()...
    438      * and AssertRCReturn(rc, rc)
    439      */
    440     if (uPass == SSM_PASS_FINAL)
    441     {
    442     }
    443     return rc;
    444 }
    445 
    446 /**
     251void virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, uint32_t cb)
     252{
     253    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     254    PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx];
     255
     256    Log2Func(("%s: %s desc_idx=%u acb=%u\n",
     257             INSTANCE(pVirtio), pQueueContext->pcszName, pBufVec->uDescIdx, cb));
     258
     259    uint32_t cbRemaining = cb;
     260
     261    for (uint32_t iSeg = 0; iSeg < pBufVec->cSegsIn && cbRemaining > 0; ++iSeg)
     262    {
     263        uint32_t cbSegLen = pBufVec->aSegsIn[iSeg].cb;
     264        if (cbSegLen > cbRemaining)   // last segment only partially used?
     265            cbSegLen = cbRemaining;
     266
     267        Assert(pBufVec->aSegsIn[iSeg].pv != NULL);
     268
     269        if (pBufVec->aSegsIn[iSeg].pv != NULL)
     270        {
     271            Log2Func(("%s: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n",
     272                     INSTANCE(pVirtio), pQueueContext->pcszName,
     273                     pQueueContext->uNextUsedIdx, iSeg,
     274                     (void *)pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv,
     275                     pBufVec->aSegsIn[iSeg].cb, cbSegLen));
     276
     277            PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
     278                 pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, cbSegLen);
     279        }
     280        cbRemaining -= cbSegLen;
     281    }
     282
     283    uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
     284    Log2Func(("%s: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n",
     285          INSTANCE(pVirtio), pQueueContext->pcszName,
     286          pQueueContext->uNextUsedIdx, uDescIdx, pBufVec->uDescIdx, cb));
     287
     288    vqWriteUsedElem(pVirtio, qIdx, pQueueContext->uNextUsedIdx, pBufVec->uDescIdx, cb);
     289}
     290
     291void virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     292{
     293    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     294    PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx];
     295
     296    uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
     297    Log2Func(("%s: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pVirtio), pQueueContext->uNextUsedIdx, uDescIdx));
     298    vqWriteUsedRingDescIdx(pVirtio, qIdx, pQueueContext->uNextUsedIdx);
     299    vqNotify(pVirtio, qIdx);
     300}
     301
     302/**
     303 *
     304 * NOTE: The consumer (PDM device) must call this function to 'forward' a relocation call.
     305 *
    447306 * Device relocation callback.
     307 *
    448308 *
    449309 * When this callback is called the device instance data, and if the
     
    464324    RT_NOREF(offDelta);
    465325    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    466 
     326    LogFunc(("%s\n", INSTANCE(pVirtio)));
     327
     328    pVirtio->pDevInsR3 = pDevIns;
    467329    pVirtio->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    468     // TBD
    469 }
    470 
    471 PVQUEUE virtioAddQueue(VIRTIOSTATE* pState, unsigned cbQueue, const char *pcszName)
    472 {
    473 
    474     RT_NOREF3(pState, cbQueue, pcszName);
    475 /* PK TODO Adapt to VirtIO 1.0
    476 
    477     PVQUEUE pQueue = NULL;
    478     // Find an empty queue slot
    479     for (unsigned i = 0; i < pState->uNumQueues; i++)
    480     {
    481         if (pState->Queues[i].VirtQ.cbQueue == 0)
    482         {
    483             pQueue = &pState->Queues[i];
    484             break;
    485         }
    486     }
    487 
    488     if (!pQueue)
    489     {
    490         Log(("%s Too many queues being added, no empty slots available!\n", INSTANCE(pState)));
    491     }
    492     else
    493     {
    494         pQueue->VirtQ.cbQueue = cbQueue;
    495         pQueue->VirtQ.addrDescriptors = 0;
    496         pQueue->uPageNumber = 0;
    497         pQueue->pfnCallback = pfnCallback;
    498         pQueue->pcszName    = pcszName;
    499     }
    500     return pQueue;
    501 */
    502     return NULL;// Temporary
    503 }
    504 
    505 
    506 
     330    pVirtio->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
     331}
     332
     333/**
     334 * Raise interrupt.
     335 *
     336 * @param   pVirtio         The device state structure.
     337 * @param   uCause          Interrupt cause bit mask to set in PCI ISR port.
     338 */
     339static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause)
     340{
     341   if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
     342       LogFlowFunc(("%s: Cause: queue interrupt\n", INSTANCE(pVirtio)));
     343   else
     344   if (uCause == VIRTIO_ISR_DEVICE_CONFIG)
     345       LogFlowFunc(("%s: Cause: device config\n", INSTANCE(pVirtio)));
     346
     347    pVirtio->uISR |= uCause;
     348    PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 1);
     349    return VINF_SUCCESS;
     350}
     351
     352/**
     353 * Lower interrupt.
     354 *
     355 * @param   pVirtio      The device state structure.
     356 */
    507357__attribute__((unused))
    508 static void virtQueueInit(PVQUEUE pQueue, uint32_t uPageNumber)
    509 {
    510     RT_NOREF2(pQueue, uPageNumber);
    511 
    512 /* PK TODO, re-work this for VirtIO 1.0
    513     pQueue->VirtQ.addrDescriptors = (uint64_t)uPageNumber << PAGE_SHIFT;
    514 
    515     pQueue->VirtQ.addrAvail = pQueue->VirtQ.addrDescriptors
    516                                 + sizeof(VIRTQ_DESC_T) * pQueue->VirtQ.cbQueue;
    517 
    518     pQueue->VirtQ.addrUsed  = RT_ALIGN(pQueue->VirtQ.addrAvail
    519             + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, ring[pQueue->VirtQ.cbQueue])
    520             + sizeof(uint16_t), // virtio 1.0 adds a 16-bit field following ring data
    521               PAGE_SIZE); // The used ring must start from the next page.
    522 
    523     pQueue->uNextAvailIndex       = 0;
    524     pQueue->uNextUsedIndex        = 0;
    525 */
    526 
    527 }
    528 
    529 
    530 __attribute__((unused))
    531 static void virtQueueReset(PVQUEUE pQueue)
    532 {
    533     RT_NOREF(pQueue);
    534 /* PK TODO Adapt to VirtIO 1.0
    535     pQueue->VirtQ.addrDescriptors = 0;
    536     pQueue->VirtQ.addrAvail       = 0;
    537     pQueue->VirtQ.addrUsed        = 0;
    538     pQueue->uNextAvailIndex           = 0;
    539     pQueue->uNextUsedIndex            = 0;
    540     pQueue->uPageNumber               = 0;
    541 */
     358static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio)
     359{
     360    LogFlowFunc(("%s\n", INSTANCE(pVirtio)));
     361    PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0);
    542362}
    543363
     
    548368 * @param   fConfigChange       - True if cfg change notification else, queue notification
    549369 */
    550 static void virtioNotifyDriver(VIRTIOHANDLE hVirtio, bool fConfigChange)
    551 {
    552    RT_NOREF(hVirtio);
    553    LogFunc(("fConfigChange = %d\n", fConfigChange));
    554 }
    555 
    556 
    557 int virtioReset(VIRTIOHANDLE hVirtio)  /* Part of our "custom API" */
    558 {
    559     PVIRTIOSTATE pVirtio = H2P(hVirtio);
    560 
    561     RT_NOREF(pVirtio);
    562 /* PK TODO Adapt to VirtIO 1.09
    563     pState->uGuestFeatures = 0;
    564     pState->uQueueSelector = 0;
    565     pState->uStatus        = 0;
    566     pState->uISR           = 0;
    567 
    568     for (unsigned i = 0; i < pState->uNumQueues; i++)
    569         virtQueueReset(&pState->Queues[i]);
    570     virtioNotify(pVirtio);
    571 */
    572     return VINF_SUCCESS;
     370__attribute__((unused))
     371static void virtioNotifyDriver(PVIRTIOSTATE pVirtio, uint8_t uCause)
     372{
     373/**
     374 * add criteria
     375 */
     376   RT_NOREF(pVirtio);
     377   if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
     378       Log2Func(("%s: Cause: queue interrupt\n", INSTANCE(pVirtio)));
     379   else
     380   if (uCause == VIRTIO_ISR_DEVICE_CONFIG)
     381       Log2Func(("%s: Cause: device config\n", INSTANCE(pVirtio)));
    573382}
    574383
     
    580389    {
    581390        pVirtio->fGenUpdatePending = true;
    582         virtioNotifyDriver(pVirtio, true);
    583     }
    584 }
     391        virtioNotifyDriver(pVirtio, VIRTIO_ISR_DEVICE_CONFIG);
     392    }
     393}
     394
     395static void vqReset(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     396{
     397    PVIRTQ_CONTEXT_T pVirtQ = &pVirtio->queueContext[qIdx];
     398    pVirtQ->uNextAvailIdx          = 0;
     399    pVirtQ->uNextUsedIdx           = 0;
     400    pVirtio->uQueueSize[qIdx]      = VIRTQ_MAX_SIZE;
     401    pVirtio->uQueueNotifyOff[qIdx] = qIdx;
     402}
     403
    585404
    586405static void virtioResetDevice(PVIRTIOSTATE pVirtio)
    587406{
    588 
    589     LogFunc(("\n"));
    590     pVirtio->uDeviceStatus          = 0;
     407    Log2Func(("\n"));
    591408    pVirtio->uDeviceFeaturesSelect  = 0;
    592409    pVirtio->uDriverFeaturesSelect  = 0;
    593410    pVirtio->uConfigGeneration      = 0;
    594     pVirtio->uNumQueues             = VIRTIO_MAX_QUEUES;
    595 
    596     for (uint32_t i = 0; i < pVirtio->uNumQueues; i++)
    597     {
    598         pVirtio->uQueueSize[i]      = VIRTQ_MAX_SIZE;
    599         pVirtio->uQueueNotifyOff[i] = i;
    600 //      virtqNotify();
    601     }
     411    pVirtio->uDeviceStatus          = 0;
     412    pVirtio->uISR                   = 0;
     413
     414#ifndef MSIX_SUPPORT
     415    /** This is required by VirtIO 1.0 specification, section 4.1.5.1.2 */
     416    pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR;
     417    for (int i = 0; i < VIRTQ_MAX_CNT; i++)
     418        pVirtio->uQueueMsixVector[i] = VIRTIO_MSI_NO_VECTOR;
     419#endif
     420
     421#if DISABLE_GUEST_DRIVER  /** Temporary debugging aid */
     422    pVirtio->uNumQueues = 0;
     423#else
     424    pVirtio->uNumQueues = VIRTQ_MAX_CNT;
     425#endif
     426    for (uint16_t qIdx = 0; qIdx < pVirtio->uNumQueues; qIdx++)
     427        vqReset(pVirtio, qIdx);
    602428}
    603429
     
    616442    int rc = VINF_SUCCESS;
    617443    uint64_t val;
    618     if (COMMON_CFG(uDeviceFeatures))
     444    if (MATCH_COMMON_CFG(uDeviceFeatures))
    619445    {
    620446        if (fWrite) /* Guest WRITE pCommonCfg>uDeviceFeatures */
     
    622448        else /* Guest READ pCommonCfg->uDeviceFeatures */
    623449        {
    624             uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures);
     450            uint32_t uIntraOff = uOffset - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures);
    625451            switch(pVirtio->uDeviceFeaturesSelect)
    626452            {
     
    628454                    val = pVirtio->uDeviceFeatures & 0xffffffff;
    629455                    memcpy((void *)pv, (const void *)&val, cb);
    630                     LOG_ACCESSOR(uDeviceFeatures);
     456                    LOG_COMMON_CFG_ACCESS(uDeviceFeatures);
    631457                    break;
    632458                case 1:
     
    634460                    uIntraOff += 4;
    635461                    memcpy((void *)pv, (const void *)&val, cb);
    636                     LOG_ACCESSOR(uDeviceFeatures);
     462                    LOG_COMMON_CFG_ACCESS(uDeviceFeatures);
    637463                    break;
    638464                default:
    639                     LogFunc(("Guest read uDeviceFeatures with out of range selector (%d), returning 0\n",
     465                    Log2Func(("Guest read uDeviceFeatures with out of range selector (%d), returning 0\n",
    640466                          pVirtio->uDeviceFeaturesSelect));
    641467                    return VERR_ACCESS_DENIED;
     
    643469        }
    644470    }
    645     else if (COMMON_CFG(uDriverFeatures))
     471    else if (MATCH_COMMON_CFG(uDriverFeatures))
    646472    {
    647473        if (fWrite) /* Guest WRITE pCommonCfg->udriverFeatures */
    648474        {
    649             uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);
     475            uint32_t uIntraOff = uOffset - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);
    650476            switch(pVirtio->uDriverFeaturesSelect)
    651477            {
    652478                case 0:
    653479                    memcpy(&pVirtio->uDriverFeatures, pv, cb);
    654                     LOG_ACCESSOR(uDriverFeatures);
     480                    LOG_COMMON_CFG_ACCESS(uDriverFeatures);
    655481                    break;
    656482                case 1:
    657483                    memcpy(((char *)&pVirtio->uDriverFeatures) + sizeof(uint32_t), pv, cb);
    658484                    uIntraOff += 4;
    659                     LOG_ACCESSOR(uDriverFeatures);
     485                    LOG_COMMON_CFG_ACCESS(uDriverFeatures);
    660486                    break;
    661487                default:
    662                     LogFunc(("Guest wrote uDriverFeatures with out of range selector (%d), returning 0\n",
     488                    Log2Func(("Guest wrote uDriverFeatures with out of range selector (%d), returning 0\n",
    663489                         pVirtio->uDriverFeaturesSelect));
    664490                    return VERR_ACCESS_DENIED;
     
    667493        else /* Guest READ pCommonCfg->udriverFeatures */
    668494        {
    669             uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);
     495            uint32_t uIntraOff = uOffset - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);
    670496            switch(pVirtio->uDriverFeaturesSelect)
    671497            {
     
    673499                    val = pVirtio->uDriverFeatures & 0xffffffff;
    674500                    memcpy((void *)pv, (const void *)&val, cb);
    675                     LOG_ACCESSOR(uDriverFeatures);
     501                    LOG_COMMON_CFG_ACCESS(uDriverFeatures);
    676502                    break;
    677503                case 1:
     
    679505                    uIntraOff += 4;
    680506                    memcpy((void *)pv, (const void *)&val, cb);
    681                     LOG_ACCESSOR(uDriverFeatures);
     507                    LOG_COMMON_CFG_ACCESS(uDriverFeatures);
    682508                    break;
    683509                default:
    684                     LogFunc(("Guest read uDriverFeatures with out of range selector (%d), returning 0\n",
     510                    Log2Func(("Guest read uDriverFeatures with out of range selector (%d), returning 0\n",
    685511                         pVirtio->uDriverFeaturesSelect));
    686512                    return VERR_ACCESS_DENIED;
     
    688514        }
    689515    }
    690     else if (COMMON_CFG(uNumQueues))
     516    else if (MATCH_COMMON_CFG(uNumQueues))
    691517    {
    692518        if (fWrite)
    693519        {
    694             LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.num_queues\n"));
     520            Log2Func(("Guest attempted to write readonly virtio_pci_common_cfg.num_queues\n"));
    695521            return VERR_ACCESS_DENIED;
    696522        }
     
    698524        {
    699525            uint32_t uIntraOff = 0;
    700             *(uint16_t *)pv = VIRTIO_MAX_QUEUES;
    701             LOG_ACCESSOR(uNumQueues);
    702         }
    703     }
    704     else if (COMMON_CFG(uDeviceStatus))
     526            *(uint16_t *)pv = VIRTQ_MAX_CNT;
     527            LOG_COMMON_CFG_ACCESS(uNumQueues);
     528        }
     529    }
     530    else if (MATCH_COMMON_CFG(uDeviceStatus))
    705531    {
    706532        if (fWrite) /* Guest WRITE pCommonCfg->uDeviceStatus */
    707533        {
    708534            pVirtio->uDeviceStatus = *(uint8_t *)pv;
    709             LogFunc(("Guest wrote uDeviceStatus ................ ("));
     535            Log2Func(("Guest wrote uDeviceStatus ................ ("));
    710536            virtioLogDeviceStatus(pVirtio->uDeviceStatus);
    711537            Log((")\n"));
    712538            if (pVirtio->uDeviceStatus == 0)
    713539                virtioResetDevice(pVirtio);
     540            pVirtio->virtioCallbacks.pfnVirtioStatusChanged(
     541                    (VIRTIOHANDLE)pVirtio, pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
    714542        }
    715543        else /* Guest READ pCommonCfg->uDeviceStatus */
    716544        {
    717             LogFunc(("Guest read  uDeviceStatus ................ ("));
     545            Log2Func(("Guest read  uDeviceStatus ................ ("));
    718546            *(uint32_t *)pv = pVirtio->uDeviceStatus;
    719547            virtioLogDeviceStatus(pVirtio->uDeviceStatus);
     
    721549        }
    722550    }
    723     else if (COMMON_CFG(uMsixConfig))
    724     {
    725         ACCESSOR(uMsixConfig);
    726     }
    727     else if (COMMON_CFG(uDeviceFeaturesSelect))
    728     {
    729         ACCESSOR(uDeviceFeaturesSelect);
    730     }
    731     else if (COMMON_CFG(uDriverFeaturesSelect))
    732     {
    733         ACCESSOR(uDriverFeaturesSelect);
    734     }
    735     else if (COMMON_CFG(uConfigGeneration))
    736     {
    737         ACCESSOR_READONLY(uConfigGeneration);
    738     }
    739     else if (COMMON_CFG(uQueueSelect))
    740     {
    741         ACCESSOR(uQueueSelect);
    742     }
    743     else if (COMMON_CFG(uQueueSize))
    744     {
    745         ACCESSOR_WITH_IDX(uQueueSize, pVirtio->uQueueSelect);
    746     }
    747     else if (COMMON_CFG(uQueueMsixVector))
    748     {
    749         ACCESSOR_WITH_IDX(uQueueMsixVector, pVirtio->uQueueSelect);
    750     }
    751     else if (COMMON_CFG(uQueueEnable))
    752     {
    753         ACCESSOR_WITH_IDX(uQueueEnable, pVirtio->uQueueSelect);
    754     }
    755     else if (COMMON_CFG(uQueueNotifyOff))
    756     {
    757         ACCESSOR_READONLY_WITH_IDX(uQueueNotifyOff, pVirtio->uQueueSelect);
    758     }
    759     else if (COMMON_CFG(uQueueDesc))
    760     {
    761         ACCESSOR_WITH_IDX(uQueueDesc, pVirtio->uQueueSelect);
    762     }
    763     else if (COMMON_CFG(uQueueAvail))
    764     {
    765         ACCESSOR_WITH_IDX(uQueueAvail, pVirtio->uQueueSelect);
    766     }
    767     else if (COMMON_CFG(uQueueUsed))
    768     {
    769         ACCESSOR_WITH_IDX(uQueueUsed, pVirtio->uQueueSelect);
     551    else if (MATCH_COMMON_CFG(uMsixConfig))
     552    {
     553        COMMON_CFG_ACCESSOR(uMsixConfig);
     554    }
     555    else if (MATCH_COMMON_CFG(uDeviceFeaturesSelect))
     556    {
     557        COMMON_CFG_ACCESSOR(uDeviceFeaturesSelect);
     558    }
     559    else if (MATCH_COMMON_CFG(uDriverFeaturesSelect))
     560    {
     561        COMMON_CFG_ACCESSOR(uDriverFeaturesSelect);
     562    }
     563    else if (MATCH_COMMON_CFG(uConfigGeneration))
     564    {
     565        COMMON_CFG_ACCESSOR_READONLY(uConfigGeneration);
     566    }
     567    else if (MATCH_COMMON_CFG(uQueueSelect))
     568    {
     569        COMMON_CFG_ACCESSOR(uQueueSelect);
     570    }
     571    else if (MATCH_COMMON_CFG(uQueueSize))
     572    {
     573        COMMON_CFG_ACCESSOR_INDEXED(uQueueSize, pVirtio->uQueueSelect);
     574    }
     575    else if (MATCH_COMMON_CFG(uQueueMsixVector))
     576    {
     577        COMMON_CFG_ACCESSOR_INDEXED(uQueueMsixVector, pVirtio->uQueueSelect);
     578    }
     579    else if (MATCH_COMMON_CFG(uQueueEnable))
     580    {
     581        COMMON_CFG_ACCESSOR_INDEXED(uQueueEnable, pVirtio->uQueueSelect);
     582    }
     583    else if (MATCH_COMMON_CFG(uQueueNotifyOff))
     584    {
     585        COMMON_CFG_ACCESSOR_INDEXED_READONLY(uQueueNotifyOff, pVirtio->uQueueSelect);
     586    }
     587    else if (MATCH_COMMON_CFG(pGcPhysQueueDesc))
     588    {
     589        COMMON_CFG_ACCESSOR_INDEXED(pGcPhysQueueDesc, pVirtio->uQueueSelect);
     590    }
     591    else if (MATCH_COMMON_CFG(pGcPhysQueueAvail))
     592    {
     593        COMMON_CFG_ACCESSOR_INDEXED(pGcPhysQueueAvail, pVirtio->uQueueSelect);
     594    }
     595    else if (MATCH_COMMON_CFG(pGcPhysQueueUsed))
     596    {
     597        COMMON_CFG_ACCESSOR_INDEXED(pGcPhysQueueUsed, pVirtio->uQueueSelect);
    770598    }
    771599    else
    772600    {
    773         LogFunc(("Bad guest %s access to virtio_pci_common_cfg: uOffset=%d, cb=%d\n",
     601        Log2Func(("Bad guest %s access to virtio_pci_common_cfg: uOffset=%d, cb=%d\n",
    774602            fWrite ? "write" : "read ", uOffset, cb));
    775603        rc = VERR_ACCESS_DENIED;
     
    794622    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    795623    int rc = VINF_SUCCESS;
    796 
    797 //#ifdef LOG_ENABLED
    798 //    LogFunc(("pVirtio=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pVirtio, GCPhysAddr, pv, cb, pv, cb));
    799 //#endif
    800624
    801625    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap,     fDevSpecific);
     
    824648        {
    825649            if (fDevSpecificFieldChanged)
    826                 LogFunc(("Dev specific config field changed since last read, gen++ = %d\n",
     650                Log2Func(("Dev specific config field changed since last read, gen++ = %d\n",
    827651                     pVirtio->uConfigGeneration));
    828652            else
    829                 LogFunc(("Config generation pending flag set, gen++ = %d\n",
     653                Log2Func(("Config generation pending flag set, gen++ = %d\n",
    830654                     pVirtio->uConfigGeneration));
    831655            ++pVirtio->uConfigGeneration;
     
    842666    if (fIsrCap)
    843667    {
    844         *(uint8_t *)pv = pVirtio->fQueueInterrupt | pVirtio->fDeviceConfigInterrupt << 1;
    845         LogFunc(("Read 0x%s from pIsrCap\n", *(uint8_t *)pv));
     668        *(uint8_t *)pv = pVirtio->uISR;
     669        Log2Func(("Read 0x%02x from uISR (virtq interrupt: %d, dev config interrupt: %d)\n",
     670              pVirtio->uISR & 0xff,
     671              pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
     672              !!(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG)));
     673        pVirtio->uISR = 0; /** VirtIO specification requires reads of ISR to clear it */
    846674    }
    847675    else {
    848676
    849         AssertMsgFailed(("virtio: Read outside of capabilities region: GCPhysAddr=%RGp cb=%RGp\n", GCPhysAddr, cb));
     677       Log2Func(("Bad read access to mapped capabilities region:\n"
     678                "                  pVirtio=%#p GCPhysAddr=%RGp cb=%u\n",
     679                pVirtio, GCPhysAddr, pv, cb, pv, cb));
    850680    }
    851681    return rc;
    852682}
    853 
    854683/**
    855684 * Memory mapped I/O Handler for PCI Capabilities write operations.
     
    869698    int rc = VINF_SUCCESS;
    870699
    871 //#ifdef LOG_ENABLED
    872 //    LogFunc(("pVirtio=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pVirtio, GCPhysAddr, pv, cb, pv, cb));
    873 //#endif
    874 
    875700    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap,     fDevSpecific);
    876701    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysCommonCfg, pVirtio->pCommonCfgCap,  fCommonCfg);
    877702    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap,    pVirtio->pIsrCap,        fIsrCap);
     703    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysNotifyCap, pVirtio->pNotifyCap,     fNotifyCap);
    878704
    879705    if (fDevSpecific)
     
    891717    if (fIsrCap)
    892718    {
    893         pVirtio->fQueueInterrupt = (*(uint8_t *)pv) & 1;
    894         pVirtio->fDeviceConfigInterrupt = !!(*((uint8_t *)pv) & 2);
    895         Log(("pIsrCap... setting fQueueInterrupt=%d fDeviceConfigInterrupt=%d\n",
    896               pVirtio->fQueueInterrupt, pVirtio->fDeviceConfigInterrupt));
     719        pVirtio->uISR = *(uint8_t *)pv;
     720        Log2Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg innterrupt: %d)\n",
     721              pVirtio->uISR & 0xff,
     722              pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
     723              !!(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG)));
    897724    }
    898725    else
    899     {
    900        LogFunc(("virtio: Write outside of capabilities region:\nGCPhysAddr=%RGp cb=%RGp,", GCPhysAddr, cb));
     726    if (fNotifyCap && cb == 2)
     727    {
     728        uint32_t uNotifyBaseOffset = GCPhysAddr - pVirtio->pGcPhysNotifyCap;
     729        uint16_t qIdx = uNotifyBaseOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER;
     730        uint16_t uNotifiedIdx = *(uint16_t *)pv;
     731        vqNotified(pVirtio, qIdx, uNotifiedIdx);
     732    }
     733    else
     734    {
     735       Log2Func(("Bad write access to mapped capabilities region:\n"
     736                "                  pVirtio=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n",
     737                pVirtio, GCPhysAddr, pv, cb, pv, cb));
    901738    }
    902739    return rc;
    903740}
    904 
    905741
    906742/**
     
    926762        if (RT_FAILURE(rc))
    927763        {
    928             LogFunc(("virtio: PCI Capabilities failed to map GCPhysAddr=%RGp cb=%RGp, region=%d\n",
     764            Log2Func(("virtio: PCI Capabilities failed to map GCPhysAddr=%RGp cb=%RGp, region=%d\n",
    929765                    GCPhysAddress, cb, iRegion));
    930766            return rc;
    931767        }
    932         LogFunc(("virtio: PCI Capabilities mapped at GCPhysAddr=%RGp cb=%RGp, region=%d\n",
     768        Log2Func(("virtio: PCI Capabilities mapped at GCPhysAddr=%RGp cb=%RGp, region=%d\n",
    933769                GCPhysAddress, cb, iRegion));
    934         pVirtio->GCPhysPciCapBase = GCPhysAddress;
    935         pVirtio->pGcPhysCommonCfg = GCPhysAddress + pVirtio->pCommonCfgCap->uOffset;
    936         pVirtio->pGcPhysNotifyCap = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset;
    937         pVirtio->pGcPhysIsrCap    = GCPhysAddress + pVirtio->pIsrCap->uOffset;
     770        pVirtio->pGcPhysPciCapBase = GCPhysAddress;
     771        pVirtio->pGcPhysCommonCfg  = GCPhysAddress + pVirtio->pCommonCfgCap->uOffset;
     772        pVirtio->pGcPhysNotifyCap  = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset;
     773        pVirtio->pGcPhysIsrCap     = GCPhysAddress + pVirtio->pIsrCap->uOffset;
    938774        if (pVirtio->pDevSpecificCap)
    939775            pVirtio->pGcPhysDeviceCap = GCPhysAddress + pVirtio->pDeviceCap->uOffset;
     
    958794                                       uint32_t uAddress, unsigned cb)
    959795{
    960 //    PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);
    961796    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
    962797
     
    971806        uint32_t pv = 0;
    972807        if (uBar == pVirtio->uVirtioCapBar)
    973             (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->GCPhysPciCapBase + uOffset),
     808            (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset),
    974809                                    &pv, uLength);
    975810        else
    976811        {
    977             LogFunc(("Guest read virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring"));
     812            Log2Func(("Guest read virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring"));
    978813            return 0;
    979814        }
    980         LogFunc(("virtio: Guest read  virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%d, length=%d, result=%d\n",
     815        Log2Func(("virtio: Guest read  virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%d, length=%d, result=%d\n",
    981816                uBar, uOffset, uLength, pv));
    982817        return pv;
     
    1015850        uint8_t  uBar    = pVirtio->pPciCfgCap->pciCap.uBar;
    1016851        if (uBar == pVirtio->uVirtioCapBar)
    1017             (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->GCPhysPciCapBase + uOffset),
     852            (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset),
    1018853                                    (void *)&u32Value, uLength);
    1019854        else
    1020855        {
    1021             LogFunc(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring"));
     856            Log2Func(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring"));
    1022857            return VINF_SUCCESS;
    1023858        }
    1024         LogFunc(("Guest wrote  virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%x, length=%x, value=%d\n",
     859        Log2Func(("Guest wrote  virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%x, length=%x, value=%d\n",
    1025860                uBar, uOffset, uLength, u32Value));
    1026861        return VINF_SUCCESS;
     
    1030865
    1031866/**
    1032  * @interface_method_impl{PDMIBASE,pfnQueryInterface}
    1033  */
    1034 void *virtioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    1035 {
    1036     VIRTIOSTATE *pThis = IFACE_TO_STATE(pInterface, IBase);
    1037     Assert(&pThis->IBase == pInterface);
    1038 
    1039     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
    1040     return NULL;
    1041 }
    1042 
    1043 /**
    1044867 * Get VirtIO accepted host-side features
    1045868 *
     
    1047870 *
    1048871 * @param   pState          Virtio state
    1049  * @param   uSelect         Selects which 32-bit set of feature information to return
    1050  */
    1051 
    1052 __attribute__((unused))
    1053 static uint64_t virtioGetHostFeatures(PVIRTIOSTATE pVirtio)
     872 */
     873uint64_t virtioGetAcceptedFeatures(PVIRTIOSTATE pVirtio)
    1054874{
    1055875    return pVirtio->uDriverFeatures;
    1056 }
    1057 
    1058 /**
    1059  *
    1060  * Set VirtIO available host-side features
    1061  *
    1062  * @returns VBox status code
    1063  *
    1064  * @param   pState              Virtio state
    1065  * @param   uDeviceFeatures    Feature bits (0-63) to set
    1066  */
    1067 
    1068 
    1069 void virtioSetHostFeatures(VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures)
    1070 {
    1071     H2P(hVirtio)->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures;
    1072876}
    1073877
     
    1080884 * @param   pState      The device state structure.
    1081885 */
    1082 int virtioDestruct(VIRTIOSTATE* pState)
    1083 {
    1084     Log(("%s Destroying PCI instance\n", INSTANCE(pState)));
     886int virtioDestruct(PVIRTIOSTATE pVirtio)
     887{
     888    RT_NOREF(pVirtio);
     889    Log(("%s Destroying PCI instance\n", INSTANCE(pVirtio)));
    1085890    return VINF_SUCCESS;
    1086891}
    1087892
    1088 /** PK (temp note to self):
    1089  *
    1090  *  Device needs to negotiate capabilities,
    1091  *  then get queue size address information from driver.
    1092  *
    1093  * Still need consumer to pass in:
    1094  *
    1095  *  num_queues
    1096  *  config_generation
    1097  *  Needs to manage feature negotiation
    1098  *  That means consumer needs to pass in device-specific feature bits/values
    1099  *  Device has to provie at least one notifier capability
    1100  *
    1101  *  ISR config value are set by the device (config interrupt vs. queue interrupt)
    1102  *
    1103  */
    1104 
    1105893/**
    1106894 * Setup PCI device controller and Virtio state
    1107895 *
    1108  * @param   pDevIns               Device instance data
    1109  * @param   pVirtio               Device State
    1110  * @param   iInstance             Instance number
    1111  * @param   pPciParams            Values to populate industry standard PCI Configuration Space data structure
    1112  * @param   pcszNameFmt           Device instance name (format-specifier)
     896 * @param   pDevIns                  Device instance data
     897 * @param   pVirtio                  Device State
     898 * @param   pPciParams               Values to populate industry standard PCI Configuration Space data structure
     899 * @param   pcszInstance             Device instance name (format-specifier)
    1113900 * @param   uNumQueues               Number of Virtio Queues created by consumer (driver)
    1114  * @param   uVirtioRegion         Region number to map for PCi Capabilities structs
    1115  * @param   devCapReadCallback    Client function to call back to handle device specific capabilities
    1116  * @param   devCapWriteCallback   Client function to call back to handle device specific capabilities
    1117  * @param   cbDevSpecificCap      Size of device specific struct
    1118  * @param   uNotifyOffMultiplier  See VirtIO 1.0 spec 4.1.4.4 re: virtio_pci_notify_cap
    1119  */
    1120 
    1121 int   virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOHANDLE phVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams,
    1122                     const char *pcszNameFmt, uint32_t uNumQueues, uint32_t uVirtioCapBar, uint64_t uDeviceFeatures,
    1123                     PFNVIRTIODEVCAPREAD devCapReadCallback, PFNVIRTIODEVCAPWRITE devCapWriteCallback,
    1124                     uint16_t cbDevSpecificCap, void *pDevSpecificCap,  uint32_t uNotifyOffMultiplier)
     901 * @param   uVirtioCapBar            Region number to map for PCi Capabilities structs
     902 * @param   uDevSpecificFeatures     VirtIO device-specific features offered by client
     903 * @param   devCapReadCallback       Client handler to call upon guest read to device specific capabilities.
     904 * @param   devCapWriteCallback      Client handler to call upon guest write to device specific capabilities.
     905 * @param   devStatusChangedCallback Client handler to call for major device status changes
     906 * @param   queueNotifiedCallback    Client handler for guest-to-host notifications that avail queue has ring data
     907 * @param   ssmLiveExecCallback      Client handler for SSM live exec
     908 * @param   ssmSaveExecCallback      Client handler for SSM save exec
     909 * @param   ssmLoadExecCallback      Client handler for SSM load exec
     910 * @param   ssmLoadDoneCallback      Client handler for SSM load done
     911 * @param   cbDevSpecificCap         Size of virtio_pci_device_cap device-specific struct
     912 */
     913int   virtioConstruct(PPDMDEVINS             pDevIns,
     914                      VIRTIOHANDLE          *phVirtio,
     915                      PVIRTIOPCIPARAMS       pPciParams,
     916                      const char             *pcszInstance,
     917                      uint32_t               uNumQueues,
     918                      uint32_t               uVirtioCapBar,
     919                      uint64_t               uDevSpecificFeatures,
     920                      PFNVIRTIODEVCAPREAD    devCapReadCallback,
     921                      PFNVIRTIODEVCAPWRITE   devCapWriteCallback,
     922                      PFNVIRTIOSTATUSCHANGED devStatusChangedCallback,
     923                      PFNVIRTIOQUEUENOTIFIED queueNotifiedCallback,
     924                      PFNSSMDEVLIVEEXEC      ssmLiveExecCallback,
     925                      PFNSSMDEVSAVEEXEC      ssmSaveExecCallback,
     926                      PFNSSMDEVLOADEXEC      ssmLoadExecCallback,
     927                      PFNSSMDEVLOADDONE      ssmLoadDoneCallback,
     928                      uint16_t               cbDevSpecificCap,
     929                      void                  *pDevSpecificCap)
    1125930{
    1126931
     
    1134939    }
    1135940
    1136 
    1137941    pVirtio->uNumQueues = uNumQueues;
    1138     pVirtio->uNotifyOffMultiplier = uNotifyOffMultiplier;
    1139     pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures;
    1140 
    1141     /* Init handles and log related stuff. */
    1142     RTStrPrintf(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszNameFmt, iInstance);
     942
     943    /**
     944     * The host features offered include both device-specific features
     945     * and reserved feature bits (device independent)
     946     */
     947    pVirtio->uDeviceFeatures = uDevSpecificFeatures
     948                             | VIRTIO_F_VERSION_1
     949                             | VIRTIO_F_RING_EVENT_IDX
     950                             | VIRTIO_F_RING_INDIRECT_DESC;
     951
     952    RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance);
    1143953
    1144954    pVirtio->pDevInsR3 = pDevIns;
     
    1147957    pVirtio->uDeviceStatus = 0;
    1148958    pVirtio->cbDevSpecificCap = cbDevSpecificCap;
    1149     pVirtio->pDevSpecificCap = pDevSpecificCap;
    1150     /**
    1151      * Need to keep a history of this relatively small virtio device-specific
    1152      * configuration buffer, which is opaque to this encapsulation of the generic
    1153      * part virtio operations, to track config changes to fields, in order to
    1154      * update the configuration generation each change. (See VirtIO 1.0 section 4.1.4.3.1)
    1155      */
     959    pVirtio->pDevSpecificCap  = pDevSpecificCap;
     960
    1156961    pVirtio->pPrevDevSpecificCap = RTMemAlloc(cbDevSpecificCap);
    1157962    if (!pVirtio->pPrevDevSpecificCap)
     
    1161966        return VERR_NO_MEMORY;
    1162967    }
     968
    1163969    memcpy(pVirtio->pPrevDevSpecificCap, pVirtio->pDevSpecificCap, cbDevSpecificCap);
    1164970    pVirtio->uVirtioCapBar = uVirtioCapBar;
    1165     pVirtio->virtioCallbacks.pfnVirtioDevCapRead = devCapReadCallback;
    1166     pVirtio->virtioCallbacks.pfnVirtioDevCapWrite = devCapWriteCallback;
     971    pVirtio->virtioCallbacks.pfnVirtioDevCapRead    = devCapReadCallback;
     972    pVirtio->virtioCallbacks.pfnVirtioDevCapWrite   = devCapWriteCallback;
     973    pVirtio->virtioCallbacks.pfnVirtioStatusChanged = devStatusChangedCallback;
     974    pVirtio->virtioCallbacks.pfnVirtioQueueNotified = queueNotifiedCallback;
     975    pVirtio->virtioCallbacks.pfnSSMDevLiveExec      = ssmLiveExecCallback;
     976    pVirtio->virtioCallbacks.pfnSSMDevSaveExec      = ssmSaveExecCallback;
     977    pVirtio->virtioCallbacks.pfnSSMDevLoadExec      = ssmLoadExecCallback;
     978    pVirtio->virtioCallbacks.pfnSSMDevLoadDone      = ssmLoadDoneCallback;
     979
    1167980
    1168981    /* Set PCI config registers (assume 32-bit mode) */
     
    11871000    }
    11881001
    1189     pVirtio->IBase = pDevIns->IBase;
     1002    rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIO_SAVEDSTATE_VERSION, sizeof(*pVirtio), NULL,
     1003                                NULL, virtioR3LiveExec, NULL, NULL, virtioR3SaveExec, NULL,
     1004                                NULL, virtioR3LoadExec, virtioR3LoadDone);
     1005    if (RT_FAILURE(rc))
     1006    {
     1007        RTMemFree(pVirtio);
     1008        return PDMDEV_SET_ERROR(pDevIns, rc,
     1009            N_("virtio: cannot register SSM callbacks"));
     1010    }
    11901011
    11911012    PDMDevHlpPCISetConfigCallbacks(pDevIns, &pVirtio->dev,
    11921013                virtioPciConfigRead,  &pVirtio->pfnPciConfigReadOld,
    11931014                virtioPciConfigWrite, &pVirtio->pfnPciConfigWriteOld);
     1015
    11941016
    11951017    /** Construct & map PCI vendor-specific capabilities for virtio host negotiation with guest driver */
     
    12011023#endif
    12021024
    1203     /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T)
     1025    /** The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T)
    12041026     * as a mandatory but suboptimal alternative interface to host device capabilities, facilitating
    12051027     * access the memory of any BAR. If the guest uses it (the VirtIO driver on Linux doesn't),
     
    12191041    pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen;
    12201042    pCfg->uBar     = uVirtioCapBar;
    1221     pCfg->uOffset  = 0;
     1043    pCfg->uOffset  = RT_ALIGN_32(0, 4); /* reminder, in case someone changes offset */
    12221044    pCfg->uLength  = sizeof(VIRTIO_PCI_COMMON_CFG_T);
    12231045    cbRegion += pCfg->uLength;
    12241046    pVirtio->pCommonCfgCap = pCfg;
    12251047
    1226     /* Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based on assumption
     1048    /** Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based on assumption
    12271049     * that each queue's uQueueNotifyOff is set equal to uQueueSelect's ordinal
    12281050     * value of the queue */
     
    12341056    pCfg->uBar     = uVirtioCapBar;
    12351057    pCfg->uOffset  = pVirtio->pCommonCfgCap->uOffset + pVirtio->pCommonCfgCap->uLength;
    1236     pCfg->uLength  = VIRTIO_MAX_QUEUES * uNotifyOffMultiplier + 2;  /* will change in VirtIO 1.1 */
     1058    pCfg->uOffset  = RT_ALIGN_32(pCfg->uOffset, 2);
     1059    pCfg->uLength  = VIRTQ_MAX_CNT * VIRTIO_NOTIFY_OFFSET_MULTIPLIER + 2;  /* will change in VirtIO 1.1 */
    12371060    cbRegion += pCfg->uLength;
    12381061    pVirtio->pNotifyCap = (PVIRTIO_PCI_NOTIFY_CAP_T)pCfg;
    1239     pVirtio->pNotifyCap->uNotifyOffMultiplier = uNotifyOffMultiplier;
    1240 
    1241     /* ISR capability (VirtIO 1.0 spec, section 4.1.4.5) */
     1062    pVirtio->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER;
     1063
     1064    /** ISR capability (VirtIO 1.0 spec, section 4.1.4.5) */
    12421065    pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
    12431066    pCfg->uCfgType = VIRTIO_PCI_CAP_ISR_CFG;
     
    12471070    pCfg->uBar     = uVirtioCapBar;
    12481071    pCfg->uOffset  = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength;
    1249     pCfg->uLength  = sizeof(uint32_t);
     1072    pCfg->uLength  = sizeof(VIRTIO_PCI_ISR_CAP_T);
    12501073    cbRegion += pCfg->uLength;
    12511074    pVirtio->pIsrCap = pCfg;
    12521075
    1253     /* PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7) */
     1076    /** PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7)
     1077     *  This capability doesn't get page-MMIO mapped. Instead uBar, uOffset and uLength are intercepted
     1078     *  by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write
     1079     *  values from any region. NOTE: The linux driver not only doesn't use this feature, and will not
     1080     *  even list it as present if uLength isn't non-zero and 4-byte-aligned as the linux driver is initializing */
     1081
    12541082    pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
    12551083    pCfg->uCfgType = VIRTIO_PCI_CAP_PCI_CFG;
     
    12571085    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CFG_CAP_T);
    12581086    pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
    1259     pCfg->uBar     = uVirtioCapBar;
    1260     pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
    1261     pCfg->uLength  = 4;  /* Initialize a non-zero 4-byte aligned so Linux virtio_pci module recognizes this cap */
     1087    pCfg->uBar     = 0;
     1088    pCfg->uOffset  = 0;
     1089    pCfg->uLength  = 0;
    12621090    cbRegion += pCfg->uLength;
    12631091    pVirtio->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg;
     
    12651093    if (pVirtio->pDevSpecificCap)
    12661094    {
    1267         /* Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the
    1268          * device specific configuration struct and passes its params to this constructor */
     1095        /** Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the
     1096         *  device-specific config fields struct and passes size to this constructor */
    12691097        pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
    12701098        pCfg->uCfgType = VIRTIO_PCI_CAP_DEVICE_CFG;
     
    12741102        pCfg->uBar     = uVirtioCapBar;
    12751103        pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
     1104        pCfg->uOffset  = RT_ALIGN_32(pCfg->uOffset, 4);
    12761105        pCfg->uLength  = cbDevSpecificCap;
    12771106        cbRegion += pCfg->uLength;
     
    12791108    }
    12801109
    1281     /* Set offset to first capability and enable PCI dev capabilities */
     1110    /** Set offset to first capability and enable PCI dev capabilities */
    12821111    PCIDevSetCapabilityList    (&pVirtio->dev, 0x40);
    12831112    PCIDevSetStatus            (&pVirtio->dev, VBOX_PCI_STATUS_CAP_LIST);
     
    12931122        rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg); /* see MsixR3init() */
    12941123        if (RT_FAILURE (rc))
    1295             /* PK TODO: The following is moot, we need to flag no MSI-X support */
     1124            /** The following is moot, we need to flag no MSI-X support */
    12961125            PCIDevSetCapabilityList(&pVirtio->dev, 0x40);
    12971126    }
    12981127
    1299     Log(("cbRegion = %d (0x%x)\n", cbRegion, cbRegion));
    1300     rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapBar, cbRegion,
     1128    /** Linux drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
     1129     * 'unknown' device-specific capability without querying the capability to figure
     1130     *  out size, so pad with an extra page */
     1131
     1132    rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapBar,  RT_ALIGN_32(cbRegion + 4096, 4096),
    13011133                                      PCI_ADDRESS_SPACE_MEM, virtioR3Map);
    13021134    if (RT_FAILURE(rc))
     
    13071139            N_("virtio: cannot register PCI Capabilities address space"));
    13081140    }
    1309     *phVirtio = (PVIRTIOHANDLE)pVirtio;
     1141    *phVirtio = (VIRTIOHANDLE)pVirtio;
    13101142    return rc;
    13111143}
     1144
     1145#ifdef VBOX_DEVICE_STRUCT_TESTCASE
     1146#  define virtioDumpState(x, s)  do {} while (0)
     1147#else
     1148#  ifdef DEBUG
     1149
     1150        static void virtioDumpState(PVIRTIOSTATE pVirtio, const char *pcszCaller)
     1151        {
     1152            Log2Func(("(called from %s)\n"
     1153                      "  uDeviceFeatures          = 0x%08x\n"
     1154                      "  uDriverFeatures          = 0x%08x\n"
     1155                      "  uDeviceFeaturesSelect    = 0x%04x\n"
     1156                      "  uGuestFeaturesSelect     = 0x%04x\n"
     1157                      "  uDeviceStatus            = 0x%02x\n"
     1158                      "  uConfigGeneration        = 0x%02x\n"
     1159                      "  uQueueSelect             = 0x%04x\n"
     1160                      "  uNumQueues               = 0x%04x\n"
     1161                      "  uISR                     = 0x%02x\n"
     1162                      "  fGenUpdatePending        = 0x%02x\n"
     1163                      "  uVirtioCapBar            = 0x%02x\n"
     1164                      "  uPciCfgDataOff           = 0x%02x\n"
     1165                      "  pGcPhysPciCapBase        = %RGp\n"
     1166                      "  pGcPhysCommonCfg         = %RGp\n"
     1167                      "  pGcPhysNotifyCap         = %RGp\n"
     1168                      "  pGcPhysIsrCap            = %RGp\n"
     1169                      "  pGcPhysDeviceCap         = %RGp\n"
     1170                      "  pDevSpecificCap          = %p\n"
     1171                      "  cbDevSpecificCap         = 0x%04x\n"
     1172                      "  pfnVirtioStatusChanged   = %p\n"
     1173                      "  pfnVirtioDevCapRead      = %p\n"
     1174                      "  pfnVirtioDevCapWrite     = %p\n"
     1175                      "  pfnPciConfigReadOld      = %p\n"
     1176                      "  pfnPciConfigWriteOld     = %p\n",
     1177                            pcszCaller,
     1178                            pVirtio->uDeviceFeatures,
     1179                            pVirtio->uDriverFeatures,
     1180                            pVirtio->uDeviceFeaturesSelect,
     1181                            pVirtio->uDriverFeaturesSelect,
     1182                            pVirtio->uDeviceStatus,
     1183                            pVirtio->uConfigGeneration,
     1184                            pVirtio->uQueueSelect,
     1185                            pVirtio->uNumQueues,
     1186                            pVirtio->uISR,
     1187                            pVirtio->fGenUpdatePending,
     1188                            pVirtio->uVirtioCapBar,
     1189                            pVirtio->uPciCfgDataOff,
     1190                            pVirtio->pGcPhysPciCapBase,
     1191                            pVirtio->pGcPhysCommonCfg,
     1192                            pVirtio->pGcPhysNotifyCap,
     1193                            pVirtio->pGcPhysIsrCap,
     1194                            pVirtio->pGcPhysDeviceCap,
     1195                            pVirtio->pDevSpecificCap,
     1196                            pVirtio->cbDevSpecificCap,
     1197                            pVirtio->virtioCallbacks.pfnVirtioStatusChanged,
     1198                            pVirtio->virtioCallbacks.pfnVirtioDevCapRead,
     1199                            pVirtio->virtioCallbacks.pfnVirtioDevCapWrite,
     1200                            pVirtio->pfnPciConfigReadOld,
     1201                            pVirtio->pfnPciConfigWriteOld
     1202            ));
     1203
     1204            for (uint16_t i = 0; i < pVirtio->uNumQueues; i++)
     1205            {
     1206                Log2Func(("%s queue:\n",
     1207                          "  queueContext[%u].uNextAvailIdx   = %u\n"
     1208                          "  queueContext[%u].uNextUsedIdx    = %u\n"
     1209                          "  uQueueSize[%u]                   = %u\n"
     1210                          "  uQueueNotifyOff[%u]              = %04x\n"
     1211                          "  uQueueMsixVector[%u]             = %04x\n"
     1212                          "  uQueueEnable[%u]                 = %04x\n"
     1213                          "  pGcPhysQueueDesc[%u]             = %RGp\n"
     1214                          "  pGcPhysQueueAvail[%u]            = %RGp\n"
     1215                          "  pGcPhysQueueUsed[%u]             = %RGp\n",
     1216                                i, pVirtio->queueContext[i].pcszName,
     1217                                i, pVirtio->queueContext[i].uNextAvailIdx,
     1218                                i, pVirtio->queueContext[i].uNextUsedIdx,
     1219                                i, pVirtio->uQueueSize[i],
     1220                                i, pVirtio->uQueueNotifyOff[i],
     1221                                i, pVirtio->uQueueMsixVector[i],
     1222                                i, pVirtio->uQueueEnable[i],
     1223                                i, pVirtio->pGcPhysQueueDesc[i],
     1224                                i, pVirtio->pGcPhysQueueAvail[i],
     1225                                i, pVirtio->pGcPhysQueueUsed[i]
     1226                ));
     1227            }
     1228        }
     1229#  endif
     1230#endif
     1231
     1232#ifdef IN_RING3
     1233
     1234 /** @callback_method_impl{FNSSMDEVSAVEEXEC}  */
     1235static DECLCALLBACK(int) virtioR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1236{
     1237    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
     1238
     1239    int rc = VINF_SUCCESS;
     1240    virtioDumpState(pVirtio, "virtioSaveExec");
     1241
     1242    rc = SSMR3PutBool(pSSM,   pVirtio->fGenUpdatePending);
     1243    rc = SSMR3PutU8(pSSM,     pVirtio->uDeviceStatus);
     1244    rc = SSMR3PutU8(pSSM,     pVirtio->uConfigGeneration);
     1245    rc = SSMR3PutU8(pSSM,     pVirtio->uPciCfgDataOff);
     1246    rc = SSMR3PutU8(pSSM,     pVirtio->uVirtioCapBar);
     1247    rc = SSMR3PutU8(pSSM,     pVirtio->uISR);
     1248    rc = SSMR3PutU16(pSSM,    pVirtio->uQueueSelect);
     1249    rc = SSMR3PutU32(pSSM,    pVirtio->uDeviceFeaturesSelect);
     1250    rc = SSMR3PutU32(pSSM,    pVirtio->uDriverFeaturesSelect);
     1251    rc = SSMR3PutU32(pSSM,    pVirtio->uNumQueues);
     1252    rc = SSMR3PutU32(pSSM,    pVirtio->cbDevSpecificCap);
     1253    rc = SSMR3PutU64(pSSM,    pVirtio->uDeviceFeatures);
     1254    rc = SSMR3PutU64(pSSM,    pVirtio->uDeviceFeatures);
     1255    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->pDevSpecificCap);
     1256    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->virtioCallbacks.pfnVirtioStatusChanged);
     1257    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->virtioCallbacks.pfnVirtioDevCapRead);
     1258    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->virtioCallbacks.pfnVirtioDevCapWrite);
     1259    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->pfnPciConfigReadOld);
     1260    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->pfnPciConfigWriteOld);
     1261    rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysCommonCfg);
     1262    rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysNotifyCap);
     1263    rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysIsrCap);
     1264    rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysDeviceCap);
     1265    rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysPciCapBase);
     1266
     1267    for (uint16_t i = 0; i < pVirtio->uNumQueues; i++)
     1268    {
     1269        rc = SSMR3PutGCPhys64(pSSM, pVirtio->pGcPhysQueueDesc[i]);
     1270        rc = SSMR3PutGCPhys64(pSSM, pVirtio->pGcPhysQueueAvail[i]);
     1271        rc = SSMR3PutGCPhys64(pSSM, pVirtio->pGcPhysQueueUsed[i]);
     1272        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueNotifyOff[i]);
     1273        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueMsixVector[i]);
     1274        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueEnable[i]);
     1275        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueSize[i]);
     1276        rc = SSMR3PutU16(pSSM,      pVirtio->queueContext[i].uNextAvailIdx);
     1277        rc = SSMR3PutU16(pSSM,      pVirtio->queueContext[i].uNextUsedIdx);
     1278        rc = SSMR3PutMem(pSSM,      pVirtio->queueContext[i].pcszName, 32);
     1279    }
     1280
     1281    rc = pVirtio->virtioCallbacks.pfnSSMDevSaveExec(pDevIns, pSSM);
     1282    return rc;
     1283}
     1284
     1285 /** @callback_method_impl{FNSSMDEVLOADEXEC}  */
     1286static DECLCALLBACK(int) virtioR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     1287{
     1288    RT_NOREF(uVersion);
     1289
     1290    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
     1291
     1292    int rc = VINF_SUCCESS;
     1293    virtioDumpState(pVirtio, "virtioLoadExec");
     1294
     1295    if (uPass == SSM_PASS_FINAL)
     1296    {
     1297        rc = SSMR3GetBool(pSSM,  &pVirtio->fGenUpdatePending);
     1298        rc = SSMR3GetU8(pSSM,    &pVirtio->uDeviceStatus);
     1299        rc = SSMR3GetU8(pSSM,    &pVirtio->uConfigGeneration);
     1300        rc = SSMR3GetU8(pSSM,    &pVirtio->uPciCfgDataOff);
     1301        rc = SSMR3GetU8(pSSM,    &pVirtio->uVirtioCapBar);
     1302        rc = SSMR3GetU8(pSSM,    &pVirtio->uISR);
     1303        rc = SSMR3GetU16(pSSM,   &pVirtio->uQueueSelect);
     1304        rc = SSMR3GetU32(pSSM,   &pVirtio->uDeviceFeaturesSelect);
     1305        rc = SSMR3GetU32(pSSM,   &pVirtio->uDriverFeaturesSelect);
     1306        rc = SSMR3GetU32(pSSM,   &pVirtio->uNumQueues);
     1307        rc = SSMR3GetU32(pSSM,   &pVirtio->cbDevSpecificCap);
     1308        rc = SSMR3GetU64(pSSM,   &pVirtio->uDeviceFeatures);
     1309        rc = SSMR3GetU64(pSSM,   &pVirtio->uDeviceFeatures);
     1310        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->pDevSpecificCap);
     1311        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioStatusChanged);
     1312        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioDevCapRead);
     1313        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioDevCapWrite);
     1314        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->pfnPciConfigReadOld);
     1315        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->pfnPciConfigWriteOld);
     1316        rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysCommonCfg);
     1317        rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysNotifyCap);
     1318        rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysIsrCap);
     1319        rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysDeviceCap);
     1320        rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysPciCapBase);
     1321
     1322        for (uint16_t i = 0; i < pVirtio->uNumQueues; i++)
     1323        {
     1324            rc = SSMR3GetGCPhys64(pSSM, &pVirtio->pGcPhysQueueDesc[i]);
     1325            rc = SSMR3GetGCPhys64(pSSM, &pVirtio->pGcPhysQueueAvail[i]);
     1326            rc = SSMR3GetGCPhys64(pSSM, &pVirtio->pGcPhysQueueUsed[i]);
     1327            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueNotifyOff[i]);
     1328            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueMsixVector[i]);
     1329            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueEnable[i]);
     1330            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueSize[i]);
     1331            rc = SSMR3GetU16(pSSM,      &pVirtio->queueContext[i].uNextAvailIdx);
     1332            rc = SSMR3GetU16(pSSM,      &pVirtio->queueContext[i].uNextUsedIdx);
     1333            rc = SSMR3GetMem(pSSM,      pVirtio->queueContext[i].pcszName, 32);
     1334        }
     1335    }
     1336
     1337    rc = pVirtio->virtioCallbacks.pfnSSMDevLoadExec(pDevIns, pSSM, uVersion, uPass);
     1338
     1339    return rc;
     1340}
     1341
     1342/** @callback_method_impl{FNSSMDEVLOADDONE}  */
     1343static DECLCALLBACK(int) virtioR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1344{
     1345    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
     1346
     1347    int rc = VINF_SUCCESS;
     1348    virtioDumpState(pVirtio, "virtioLoadDone");
     1349
     1350    rc = pVirtio->virtioCallbacks.pfnSSMDevLoadDone(pDevIns, pSSM);
     1351
     1352    return rc;
     1353}
     1354
     1355/** @callback_method_impl{FNSSMDEVLIVEEXEC}  */
     1356static DECLCALLBACK(int) virtioR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
     1357{
     1358    PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
     1359
     1360    int rc = VINF_SUCCESS;
     1361    virtioDumpState(pVirtio, "virtioLiveExec");
     1362
     1363    rc = pVirtio->virtioCallbacks.pfnSSMDevLiveExec(pDevIns, pSSM, uPass);
     1364
     1365    return rc;
     1366
     1367}
     1368
     1369
    13121370#endif /* IN_RING3 */
    13131371
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r80194 r80219  
    2424#include <iprt/ctype.h>
    2525
    26 #define VIRTQ_MAX_SIZE                      1024
    27 #define VIRTIO_MAX_QUEUES                   256     /** Max queues we allow guest to create      */
     26typedef void * VIRTIOHANDLE;                                     /**< Opaque handle to the VirtIO framework */
     27
     28#define DISABLE_GUEST_DRIVER 0
     29
     30/**
     31 * Important sizing and bounds params for this impl. of VirtIO 1.0 PCI device
     32 */
     33 /**** Temporary values for debugging */
     34#define VIRTQ_MAX_SIZE                      16                  /**< Max size (# desc elements) of a virtq    */
     35#define VIRTQ_MAX_CNT                       24                  /**< Max queues we allow guest to create      */
     36#define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
    2837#define VIRTQ_DESC_MAX_SIZE                 (2 * 1024 * 1024)
    2938
    30 typedef void * VIRTIOHANDLE;                        /** opaque handle to the VirtIO framework */
    31 typedef VIRTIOHANDLE *PVIRTIOHANDLE;
    32 
    33 /** Reserved Feature Bits */
    34 #define VIRTIO_F_RING_INDIRECT_DESC         RT_BIT_64(28)
    35 #define VIRTIO_F_RING_IDX                   RT_BIT_64(29)
    36 #define VIRTIO_F_VERSION_1                  RT_BIT_64(32)
    37 
    38 #define VIRTIO_MSI_NO_VECTOR                0xffff  /* Vector value used to disable MSI for queue */
    39 
    40 /** Device Status field constants (from Virtio 1.0 spec) */
    41 #define VIRTIO_STATUS_ACKNOWLEDGE           0x01    /** Guest found this emulated PCI device     */
    42 #define VIRTIO_STATUS_DRIVER                0x02    /** Guest can drive this PCI device          */
    43 #define VIRTIO_STATUS_DRIVER_OK             0x04    /** Guest VirtIO driver setup and ready      */
    44 #define VIRTIO_STATUS_FEATURES_OK           0x08    /** Guest says feature negotiation complete  */
    45 #define VIRTIO_STATUS_FAILED                0x80    /** Fatal: Something wrong, guest gave up    */
    46 #define VIRTIO_STATUS_DEVICE_NEEDS_RESET    0x40    /** Device experienced unrecoverable error   */
    47 
    48 /** virtq related flags */
    49 #define VIRTQ_DESC_F_NEXT                   1       /** Indicates this descriptor chains to next */
    50 #define VIRTQ_DESC_F_WRITE                  2       /** Marks buffer as write-only (default ro)  */
    51 #define VIRTQ_DESC_F_INDIRECT               4       /** Buffer is list of buffer descriptors     */
    52 #define VIRTIO_F_INDIRECT_DESC              28      /** Using indirect descriptors               */
    53 #define VIRTIO_F_EVENT_IDX                  29      /** avail_event, used_event in play          */
    54 
    55 #define VIRTQ_USED_F_NO_NOTIFY              1       /** Optimization: Device advises driver (unreliably):
    56                                                         Don't kick me when adding buffer */
    57 
    58 #define VIRTQ_AVAIL_F_NO_INTERRUPT          1       /** Optimization: Driver advises device (unreliably):
    59                                                         Don't interrupt when buffer consumed */
    60 /**
    61  * virtq related structs
    62  *  (struct names follow VirtIO 1.0 spec, typedef use VBox style)
    63  */
    64 typedef struct virtq_desc
    65 {
    66     uint64_t  pGcPhysBuf;                   /** addr        GC physical address of buffer   */
    67     uint32_t  cbBuf;                        /** len         Buffer length                   */
    68     uint16_t  fFlags;                       /** flags       Buffer specific flags           */
    69     uint16_t  uNext;                        /** next        Chain idx if VIRTIO_DESC_F_NEXT */
    70 } VIRTQ_DESC_T, *PVIRTQ_DESC_T;
    71 
    72 typedef struct virtq_avail  /* VirtIO 1.0 specification formal name of this struct    */
    73 {
    74     uint16_t  fFlags;                       /** flags       avail ring guest-to-host flags */
    75     uint16_t  uIdx;                         /** idx         Index of next free ring slot    */
    76     uint16_t  auRing[1];                    /** ring        Ring: avail guest-to-host bufs  */
    77     uint16_t  uUsedEventIdx;                /** used_event  (if VIRTQ_USED_F_NO_NOTIFY)     */
    78 } VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
    79 
    80 typedef struct virtq_used_elem /* VirtIO 1.0 specification formal name of this struct */
    81 {
    82     uint32_t  uIdx;                         /** idx         Start of used descriptor chain  */
    83     uint32_t  cbElem;                       /** len         Total len of used desc chain    */
    84 } VIRTQ_USED_ELEM_T;
    85 
    86 typedef struct virt_used  /* VirtIO 1.0 specification formal name of this struct */
    87 {
    88     uint16_t  fFlags;                       /** flags       used ring host-to-guest flags  */
    89     uint16_t  uIdx;                         /** idx         Index of next ring slot        */
    90     VIRTQ_USED_ELEM_T aRing[1];             /** ring        Ring: used host-to-guest bufs  */
    91     uint16_t  uAvailEventIdx;               /** avail_event if (VIRTQ_USED_F_NO_NOTIFY)    */
    92 } VIRTQ_USED_T, *PVIRTQ_USED_T;
    93 
    94 
    95 typedef struct virtq
    96 {
    97     uint16_t cbQueue;                       /** virtq size                                 */
    98     uint16_t padding[3];                    /** 64-bit-align phys ptrs to start of struct  */
    99     RTGCPHYS pGcPhysVirtqDescriptors;       /** (struct virtq_desc  *)                     */
    100     RTGCPHYS pGcPhysVirtqAvail;             /** (struct virtq_avail *)                     */
    101     RTGCPHYS pGcPhysVirtqUsed;              /** (struct virtq_used  *)                     */
    102 } VIRTQ, *PVIRTQ;
    103 
    104 typedef struct VQueue
    105 {
    106     VIRTQ VirtQ;
    107     uint16_t  uNextAvailIndex;
    108     uint16_t  uNextUsedIndex;
    109     uint32_t  uPageNumber;
    110     R3PTRTYPE(const char *) pcszName;
    111 } VQUEUE;
    112 
    113 
    114 typedef VQUEUE *PVQUEUE;
    115 
    116 typedef struct VQueueElemSeg
    117 {
    118     RTGCPHYS addr;
    119     void    *pv;
    120     uint32_t cb;
    121 } VQUEUESEG;
    122 
    123 typedef struct VQueueElem
    124 {
    125     uint32_t  idx;
    126     uint32_t  cSegsIn;
    127     uint32_t  cSegsOut;
    128     VQUEUESEG aSegsIn[VIRTQ_MAX_SIZE];
    129     VQUEUESEG aSegsOut[VIRTQ_MAX_SIZE];
    130 } VQUEUEELEM;
    131 typedef VQUEUEELEM *PVQUEUEELEM;
     39typedef struct VIRTQ_SEG                                         /**< Describes one segment of a buffer vector */
     40{
     41    RTGCPHYS addr;                                               /**< Physical addr. of this segment's buffer  */
     42    void    *pv;                                                 /**< Buf to hold value to write or read       */
     43    uint32_t cb;                                                 /**< Number of bytes to write or read         */
     44} VIRTQ_SEG_T;
     45
     46typedef struct VIRTQ_BUF_VECTOR                                  /**< Scatter/gather buffer vector             */
     47{
     48    uint32_t    uDescIdx;                                        /**< Desc at head of this vector list         */
     49    uint32_t    cSegsIn;                                         /**< Count of segments in aSegsIn[]           */
     50    uint32_t    cSegsOut;                                        /**< Count of segments in aSegsOut[]          */
     51    VIRTQ_SEG_T aSegsIn[VIRTQ_MAX_SIZE];                         /**< List of segments to write to guest       */
     52    VIRTQ_SEG_T aSegsOut[VIRTQ_MAX_SIZE];                        /**< List of segments read from guest         */
     53} VIRTQ_BUF_VECTOR_T, *PVIRTQ_BUF_VECTOR_T;
    13254
    13355/**
    13456 * The following structure is used to pass the PCI parameters from the consumer
    135  * to this generic VirtIO framework
     57 * to this generic VirtIO framework. This framework provides the Vendor ID as Virtio.
    13658 */
    13759typedef struct VIRTIOPCIPARAMS
    13860{
    139     uint16_t  uDeviceId;
    140     uint16_t  uClassBase;
    141     uint16_t  uClassSub;
    142     uint16_t  uClassProg;
    143     uint16_t  uSubsystemId;
    144     uint16_t  uSubsystemVendorId;
    145     uint16_t  uRevisionId;
    146     uint16_t  uInterruptLine;
    147     uint16_t  uInterruptPin;
     61    uint16_t  uDeviceId;                                         /**< PCI Cfg Device ID                        */
     62    uint16_t  uClassBase;                                        /**< PCI Cfg Base Class                       */
     63    uint16_t  uClassSub;                                         /**< PCI Cfg Subclass                         */
     64    uint16_t  uClassProg;                                        /**< PCI Cfg Programming Interface Class      */
     65    uint16_t  uSubsystemId;                                      /**< PCI Cfg Card Manufacturer Vendor ID      */
     66    uint16_t  uSubsystemVendorId;                                /**< PCI Cfg Chipset Manufacturer Vendor ID   */
     67    uint16_t  uRevisionId;                                       /**< PCI Cfg Revision ID                      */
     68    uint16_t  uInterruptLine;                                    /**< PCI Cfg Interrupt line                   */
     69    uint16_t  uInterruptPin;                                     /**< PCI Cfg InterruptPin                     */
    14870} VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS;
    14971
     72/**
     73 * Implementation-specific client callback to notify client of significant device status
     74 * changes.
     75 *
     76 * @param hVirtio       Handle to VirtIO framework
     77 * @param fDriverOk     True if guest driver is okay (thus queues, etc... are valid)
     78 */
     79typedef DECLCALLBACK(void)   FNVIRTIOSTATUSCHANGED(VIRTIOHANDLE hVirtio, bool fDriverOk);
     80typedef FNVIRTIOSTATUSCHANGED *PFNVIRTIOSTATUSCHANGED;
     81
     82/**
     83 * When guest-to-host queue notifications are enabled, the guest driver notifies the host
     84 * that the avail queue has buffers, and this callback informs the client.
     85 *
     86 * @param   hVirtio     Handle to the VirtIO framework
     87 * @param   qIdx        Index of the notified queue
     88 */
     89typedef DECLCALLBACK(void)   FNVIRTIOQUEUENOTIFIED(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     90typedef FNVIRTIOQUEUENOTIFIED *PFNVIRTIOQUEUENOTIFIED;
     91
    15092 /**
    151  * VirtIO Device-specific capabilities read callback
     93 * Implementation-specific client callback to access VirtIO Device-specific capabilities
    15294 * (other VirtIO capabilities and features are handled in VirtIO implementation)
    15395 *
     
    161103
    162104/**
    163  * VirtIO Device-specific capabilities read callback
     105 * Implementation-specific client ballback to access VirtIO Device-specific capabilities
    164106 * (other VirtIO capabilities and features are handled in VirtIO implementation)
    165107 *
     
    172114typedef FNVIRTIODEVCAPREAD *PFNVIRTIODEVCAPREAD;
    173115
     116
    174117/** @name VirtIO port I/O callbacks.
    175118 * @{ */
    176119typedef struct VIRTIOCALLBACKS
    177120{
    178      DECLCALLBACKMEMBER(int,      pfnVirtioDevCapRead)
    179                                       (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbRead);
    180      DECLCALLBACKMEMBER(int,      pfnVirtioDevCapWrite)
    181                                       (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbWrite);
     121     DECLCALLBACKMEMBER(void, pfnVirtioStatusChanged)
     122                                  (VIRTIOHANDLE hVirtio, bool fDriverOk);
     123     DECLCALLBACKMEMBER(void, pfnVirtioQueueNotified)
     124                                  (VIRTIOHANDLE hVirtio, uint16_t qIdx);
     125     DECLCALLBACKMEMBER(int,  pfnVirtioDevCapRead)
     126                                  (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbRead);
     127     DECLCALLBACKMEMBER(int,  pfnVirtioDevCapWrite)
     128                                  (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbWrite);
     129     DECLCALLBACKMEMBER(int,  pfnSSMDevLiveExec)
     130                                  (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass);
     131     DECLCALLBACKMEMBER(int,  pfnSSMDevSaveExec)
     132                                  (PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
     133     DECLCALLBACKMEMBER(int,  pfnSSMDevLoadExec)
     134                                  (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
     135     DECLCALLBACKMEMBER(int,  pfnSSMDevLoadDone)
     136                                  (PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
     137
    182138} VIRTIOCALLBACKS, *PVIRTIOCALLBACKS;
    183139/** @} */
    184140
    185 PVQUEUE virtioAddQueue(         VIRTIOHANDLE hVirtio, uint32_t uSize, const char *pcszName);
    186 int     virtioDestruct(         VIRTIOHANDLE hVirtio);
    187 int     virtioReset(            VIRTIOHANDLE hVirtio);
    188 void    virtioSetReadLed(       VIRTIOHANDLE hVirtio, bool fOn);
    189 void    virtioSetWriteLed(      VIRTIOHANDLE hVirtio, bool fOn);
    190 int     virtioRaiseInterrupt(   VIRTIOHANDLE hVirtio, int rcBusy, uint8_t uint8_tIntCause);
    191 //void    virtioNotifyDriver(     VIRTIOHANDLE hVirtio);
    192 void    virtioSetHostFeatures(  VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures);
    193 
    194 bool    virtQueueSkip(          VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
    195 bool    virtQueueGet(           VIRTIOHANDLE hVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true);
    196 void    virtQueuePut(           VIRTIOHANDLE hVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t len, uint32_t uReserved = 0);
    197 void    virtQueueNotify(        VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
    198 void    virtQueueSync(          VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
    199 void    vringSetNotification(   VIRTIOHANDLE hVirtio, PVIRTQ pVirtQ, bool fEnabled);
    200 
    201 /**
    202  * Formats the logging of a memory-mapped I/O input or output value
     141int           virtioReset        (VIRTIOHANDLE hVirtio);
     142bool          virtioQueueInit    (VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName);
     143const char *  virtioQueueGetName (VIRTIOHANDLE hVirtio, uint16_t qIdx);
     144bool          virtioQueueGet     (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, bool fRemove);
     145void          virtioQueuePut     (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, uint32_t cb);
     146bool          virtioQueuePeek    (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec);
     147void          virtioQueueSync    (VIRTIOHANDLE hVirtio, uint16_t qIdx);
     148bool          virtioQueueIsEmpty (VIRTIOHANDLE hVirtio, uint16_t qIdx);
     149int           virtioGetNumQueues (VIRTIOHANDLE hVirtio);
     150
     151/** CLIENT MUST CALL ON RELOCATE CALLBACK! */
     152void    virtioRelocate(         PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
     153
     154/**
     155 * Log memory-mapped I/O input or output value
    203156 *
    204157 * @param   pszFunc     - To avoid displaying this function's name via __FUNCTION__ or LogFunc()
     
    211164 * @param   idx         - The index if fHasIndex
    212165 */
    213 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember,
     166void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, size_t uMemberSize,
    214167                            const void *pv, uint32_t cb, uint32_t uOffset,
    215168                            bool fWrite, bool fHasIndex, uint32_t idx);
    216169
    217 int     virtioConstruct(
    218             PPDMDEVINS           pDevIns,
    219             PVIRTIOHANDLE        phVirtio,
    220             int                  iInstance,
    221             PVIRTIOPCIPARAMS     pPciParams,
    222             const char           *pcszNameFmt,
    223             uint32_t             nQueues,
    224             uint32_t             uVirtioCapBar,
    225             uint64_t             uDeviceFeatures,
    226             PFNVIRTIODEVCAPREAD  devCapReadCallback,
    227             PFNVIRTIODEVCAPWRITE devCapWriteCallback,
    228             uint16_t             cbDevSpecificCap,
    229             void                 *pDevSpecificCap,
    230             uint32_t             uNotifyOffMultiplier);
    231 
    232 //PCIDevGetCapabilityList
    233 //PCIDevSetCapabilityList
    234 //DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset)
    235 //    PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset);
    236 //DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PPDMPCIDEV pPciDev)
    237 //    return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST);
     170/**
     171 * Setup PCI device controller and Virtio state
     172 *
     173 * @param   pDevIns                  Device instance data
     174 * @param   pVirtio                  Device State
     175 * @param   pPciParams               Values to populate industry standard PCI Configuration Space data structure
     176 * @param   pcszInstance             Device instance name
     177 * @param   uNumQueues               Number of Virtio Queues created by consumer (driver)
     178 * @param   uVirtioCapBar            Region number to map for PCi Capabilities structs
     179 * @param   uDevSpecificFeatures     VirtIO device-specific features offered by client
     180 * @param   devCapReadCallback       Client handler to call upon guest read to device specific capabilities.
     181 * @param   devCapWriteCallback      Client handler to call upon guest write to device specific capabilities.
     182 * @param   devStatusChangedCallback Client handler to call for major device status changes
     183 * @param   queueNotifiedCallback    Client handler for guest-to-host notifications that avail queue has ring data
     184 * @param   ssmLiveExecCallback      Client handler for SSM live exec
     185 * @param   ssmSaveExecCallback      Client handler for SSM save exec
     186 * @param   ssmLoadExecCallback      Client handler for SSM load exec
     187 * @param   ssmLoadDoneCallback      Client handler for SSM load done
     188 * @param   cbDevSpecificCap         Size of virtio_pci_device_cap device-specific struct
     189 */
     190int  virtioConstruct(PPDMDEVINS             pDevIns,
     191                     VIRTIOHANDLE          *phVirtio,
     192                     PVIRTIOPCIPARAMS       pPciParams,
     193                     const char            *pcszInstance,
     194                     uint32_t               nQueues,
     195                     uint32_t               uVirtioCapBar,
     196                     uint64_t               uDevSpecificFeatures,
     197                     PFNVIRTIODEVCAPREAD    devCapReadCallback,
     198                     PFNVIRTIODEVCAPWRITE   devCapWriteCallback,
     199                     PFNVIRTIOSTATUSCHANGED devStatusChangedCallback,
     200                     PFNVIRTIOQUEUENOTIFIED queueNotifiedCallback,
     201                     PFNSSMDEVLIVEEXEC      ssmLiveExecCallback,
     202                     PFNSSMDEVSAVEEXEC      ssmSaveExecCallback,
     203                     PFNSSMDEVLOADEXEC      ssmLoadExecCallback,
     204                     PFNSSMDEVLOADDONE      ssmLoadDoneCallback,
     205                     uint16_t               cbDevSpecificCap,
     206                     void                  *pDevSpecificCap);
    238207
    239208#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_h */
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r80201 r80219  
    2424#include "Virtio_1_0.h"
    2525
    26 
    27 
    2826/** @name Saved state versions.
    2927 * The saved state version is changed if either common or any of specific
     
    3230 * for example.
    3331 */
    34 #define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1
    35 #define VIRTIO_SAVEDSTATE_VERSION           2
     32#define VIRTIO_SAVEDSTATE_VERSION                       1
    3633/** @} */
    3734
    38 #define DEVICE_PCI_VENDOR_ID_VIRTIO         0x1AF4  /** Mandatory, so VirtIO driver can find this device */
    39 #define DEVICE_PCI_REVISION_ID_VIRTIO       1       /** Virtio spec suggests >= 1 for non-transitional drivers */
    40 
     35#define VIRTIO_ISR_VIRTQ_INTERRUPT           RT_BIT_32(0)
     36#define VIRTIO_ISR_DEVICE_CONFIG             RT_BIT_32(1)
     37#define DEVICE_PCI_VENDOR_ID_VIRTIO                0x1AF4        /**< Required: VirtIO driver uses to find dev  */
     38#define DEVICE_PCI_REVISION_ID_VIRTIO                   1        /**< VirtIO 1.0 non-transitional drivers >= 1  */
     39
     40/** Reserved (*negotiated*) Feature Bits (e.g. device independent features, VirtIO 1.0 spec,section 6) */
     41
     42#define VIRTIO_F_RING_INDIRECT_DESC         RT_BIT_64(28)        /**< Allow descs to point to list of descs     */
     43#define VIRTIO_F_INDIRECT_DESC              RT_BIT_64(28)        /**< Doc bug: Bit has 2 names in VirtIO 1.0-04 */
     44#define VIRTIO_F_RING_EVENT_IDX             RT_BIT_64(29)        /**< Allow notification disable for n elems    */
     45#define VIRTIO_F_EVENT_IDX                  RT_BIT_64(29)        /**< Doc bug: Bit has 2 names in VirtIO 1.0-04 */
     46#define VIRTIO_F_VERSION_1                  RT_BIT_64(32)
     47
     48#define VIRTIO_MSI_NO_VECTOR                       0xffff        /**< Vector value to disable MSI for queue     */
     49
     50/** Device Status field constants (from Virtio 1.0 spec) */
     51#define VIRTIO_STATUS_ACKNOWLEDGE                   0x01         /**< Guest driver: Located this VirtIO device  */
     52#define VIRTIO_STATUS_DRIVER                        0x02         /**< Guest driver: Can drive this VirtIO dev.  */
     53#define VIRTIO_STATUS_DRIVER_OK                     0x04         /**< Guest driver: Driver set-up and ready     */
     54#define VIRTIO_STATUS_FEATURES_OK                   0x08         /**< Guest driver: Feature negotiation done    */
     55#define VIRTIO_STATUS_FAILED                        0x80         /**< Guest driver: Fatal error, gave up        */
     56#define VIRTIO_STATUS_DEVICE_NEEDS_RESET            0x40         /**< Device experienced unrecoverable error    */
     57
     58/* @def Virtio Device PCI Capabilities type codes */
     59#define VIRTIO_PCI_CAP_COMMON_CFG                     1          /**< Common configuration PCI capability ID    */
     60#define VIRTIO_PCI_CAP_NOTIFY_CFG                     2          /**< Notification area PCI capability ID       */
     61#define VIRTIO_PCI_CAP_ISR_CFG                        3          /**< ISR PCI capability id                     */
     62#define VIRTIO_PCI_CAP_DEVICE_CFG                     4          /**< Device-specific PCI cfg capability ID     */
     63#define VIRTIO_PCI_CAP_PCI_CFG                        5          /**< PCI CFG capability ID                     */
     64
     65#define VIRTIO_PCI_CAP_ID_VENDOR                   0x09          /**< Vendor-specific PCI CFG Device Cap. ID    */
    4166
    4267/**
    4368 * The following is the PCI capability struct common to all VirtIO capability types
    4469 */
    45 #define VIRTIO_PCI_CAP_ID_VENDOR       0x09 /** Vendor-specific PCI CFG Device Capability ID */
    46 
    4770typedef struct virtio_pci_cap
    4871{
    4972    /* All little-endian */
    50     uint8_t   uCapVndr;                     /** Generic PCI field: PCI_CAP_ID_VNDR          */
    51     uint8_t   uCapNext;                     /** Generic PCI field: next ptr.                */
    52     uint8_t   uCapLen;                      /** Generic PCI field: capability length        */
    53     uint8_t   uCfgType;                     /** Identifies the structure.                   */
    54     uint8_t   uBar;                         /** Where to find it.                           */
    55     uint8_t   uPadding[3];                  /** Pad to full dword.                          */
    56     uint32_t  uOffset;                      /** Offset within bar.  (L.E.)                  */
    57     uint32_t  uLength;                      /** Length of struct, in bytes. (L.E.)          */
     73    uint8_t   uCapVndr;                                          /**< Generic PCI field: PCI_CAP_ID_VNDR        */
     74    uint8_t   uCapNext;                                          /**< Generic PCI field: next ptr.              */
     75    uint8_t   uCapLen;                                           /**< Generic PCI field: capability length      */
     76    uint8_t   uCfgType;                                          /**< Identifies the structure.                 */
     77    uint8_t   uBar;                                              /**< Where to find it.                         */
     78    uint8_t   uPadding[3];                                       /**< Pad to full dword.                        */
     79    uint32_t  uOffset;                                           /**< Offset within bar.  (L.E.)                */
     80    uint32_t  uLength;                                           /**< Length of struct, in bytes. (L.E.)        */
    5881}  VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T;
    5982
    6083/**
    61  * The following structs correspond to the VirtIO capability types and describe
    62  * fields accessed by MMIO via the relevant BAR. virtio_pci_dev_cap is not listed
    63  * here because it is device specific, thus the device specific implementation
    64  * consumer of this framework passes a ref/size in the constructor
     84 * Local implementation's per-queue usage (e.g. not part of VirtIO specification)
     85 */
     86typedef struct VIRTQ_CONTEXT
     87{
     88    const char *pcszName[32];                                   /**< Dev-specific name of queue                */
     89    uint16_t    uNextAvailIdx;                                  /**< Consumer's position in avail ring         */
     90    uint16_t    uNextUsedIdx;                                   /**< Consumer's position in used ring          */
     91} VIRTQ_CONTEXT_T, *PVIRTQ_CONTEXT_T;
     92
     93/**
     94 * VirtIO 1.0 Capabilities' related MMIO-mapped structs:
    6595 *
    66  */
    67 
    68 /* Virtio Device PCI Capabilities type codes */
    69 #define VIRTIO_PCI_CAP_COMMON_CFG      1    /** Common configuration PCI capability ID */
    70 #define VIRTIO_PCI_CAP_NOTIFY_CFG      2    /** Notification area PCI capability ID */
    71 #define VIRTIO_PCI_CAP_ISR_CFG         3    /** ISR PCI capability id */
    72 #define VIRTIO_PCI_CAP_DEVICE_CFG      4    /** Device specific configuration PCI capability ID */
    73 #define VIRTIO_PCI_CAP_PCI_CFG         5    /** PCI CFG capability ID */
    74 
    75 typedef struct virtio_pci_common_cfg /* VirtIO 1.0 specification name of this struct  */
     96 * Note: virtio_pci_device_cap is dev-specific, implemented by client. Definition unknown here.
     97 */
     98typedef struct virtio_pci_common_cfg
    7699{
    77100    /* Per device fields */
    78     uint32_t  uDeviceFeaturesSelect;        /** RW (driver selects device features)         */
    79     uint32_t  uDeviceFeatures;              /** RO (device reports features to driver)      */
    80     uint32_t  uDriverFeaturesSelect;        /** RW (driver selects driver features)         */
    81     uint32_t  uDriverFeatures;              /** RW (driver accepts device features)         */
    82     uint16_t  uMsixConfig;                  /** RW (driver sets MSI-X config vector)        */
    83     uint16_t  uNumQueues;                   /** RO (device specifies max queues)            */
    84     uint8_t   uDeviceStatus;                /** RW (driver writes device status, 0 resets)  */
    85     uint8_t   uConfigGeneration;            /** RO (device changes when changing configs)  */
     101    uint32_t  uDeviceFeaturesSelect;                             /**< RW (driver selects device features)       */
     102    uint32_t  uDeviceFeatures;                                   /**< RO (device reports features to driver)    */
     103    uint32_t  uDriverFeaturesSelect;                             /**< RW (driver selects driver features)       */
     104    uint32_t  uDriverFeatures;                                   /**< RW (driver accepts device features)       */
     105    uint16_t  uMsixConfig;                                       /**< RW (driver sets MSI-X config vector)      */
     106    uint16_t  uNumQueues;                                        /**< RO (device specifies max queues)          */
     107    uint8_t   uDeviceStatus;                                     /**< RW (driver writes device status, 0 resets)*/
     108    uint8_t   uConfigGeneration;                                 /**< RO (device changes when changing configs) */
    86109
    87110    /* Per virtqueue fields (as determined by uQueueSelect) */
    88     uint16_t  uQueueSelect;                 /** RW (selects queue focus for these fields)  */
    89     uint16_t  uQueueSize;                   /** RW (queue size, 0 - 2^n)                    */
    90     uint16_t  uQueueMsixVector;             /** RW (driver selects MSI-X queue vector)      */
    91     uint16_t  uQueueEnable;                 /** RW (driver controls usability of queue)     */
    92     uint16_t  uQueueNotifyOff;              /** RO (offset uto virtqueue; see spec)         */
    93     uint64_t  uQueueDesc;                   /** RW (driver writes desc table phys addr)     */
    94     uint64_t  uQueueAvail;                  /** RW (driver writes avail ring phys addr)     */
    95     uint64_t  uQueueUsed;                   /** RW (driver writes used ring  phys addr)     */
     111    uint16_t  uQueueSelect;                                      /**< RW (selects queue focus for these fields) */
     112    uint16_t  uQueueSize;                                        /**< RW (queue size, 0 - 2^n)                  */
     113    uint16_t  uQueueMsixVector;                                  /**< RW (driver selects MSI-X queue vector)    */
     114    uint16_t  uQueueEnable;                                      /**< RW (driver controls usability of queue)   */
     115    uint16_t  uQueueNotifyOff;                                   /**< RO (offset uto virtqueue; see spec)       */
     116    uint64_t  pGcPhysQueueDesc;                                  /**< RW (driver writes desc table phys addr)   */
     117    uint64_t  pGcPhysQueueAvail;                                 /**< RW (driver writes avail ring phys addr)   */
     118    uint64_t  pGcPhysQueueUsed;                                  /**< RW (driver writes used ring  phys addr)   */
    96119} VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T;
    97120
    98121typedef struct virtio_pci_notify_cap
    99122{
    100     struct virtio_pci_cap pciCap;
    101     uint32_t uNotifyOffMultiplier;          /* notify_off_multiplier                       */
    102 } VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T;
     123    struct virtio_pci_cap pciCap;                                /**< Notification MMIO mapping capability      */
     124    uint32_t uNotifyOffMultiplier;                               /**< notify_off_multiplier                     */
     125}  VIRTIO_PCI_NOTIFY_CAP_T,  *PVIRTIO_PCI_NOTIFY_CAP_T;
    103126
    104127typedef struct virtio_pci_cfg_cap
    105128{
    106     struct virtio_pci_cap pciCap;
    107     uint8_t uPciCfgData[4]; /* Data for BAR access. */
    108 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T;
     129    struct virtio_pci_cap pciCap;                                /**< Cap. defines the BAR/off/len to access    */
     130    uint8_t uPciCfgData[4];                                      /**< I/O buf for above cap.                    */
     131} VIRTIO_PCI_CFG_CAP_T,   *PVIRTIO_PCI_CFG_CAP_T;
     132
     133/** For ISR, spec says min. 1 byte. Diagram shows 32-bits, mostly reserved */
     134typedef uint32_t VIRTIO_PCI_ISR_CAP_T, *PVIRTIO_PCI_ISR_CAP_T;
    109135
    110136/**
     
    115141typedef struct VIRTIOSTATE
    116142{
    117     PDMPCIDEV                    dev;
    118     PDMCRITSECT                  cs;                                    /**< Critical section - what is it protecting? */
    119     /* Read-only part, never changes after initialization. */
    120     char                         szInstance[8];                         /**< Instance name, e.g. VNet#1. */
    121 
    122 #if HC_ARCH_BITS != 64
    123     uint32_t                     padding1;
    124 #endif
    125 
    126     /** Status LUN: Base interface. */
    127     PDMIBASE                     IBase;
    128 
    129     /** Status LUN: LED port interface. */
    130     PDMILEDPORTS                 ILed;
    131 
    132     /* Read/write part, protected with critical section. */
    133     /** Status LED. */
    134     PDMLED                       led;
    135 
    136     VIRTIOCALLBACKS              virtioCallbacks;
    137 
    138     /** Status LUN: LED connector (peer). */
    139     R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
    140 
    141     PPDMDEVINSR3                 pDevInsR3;                           /**< Device instance - R3. */
    142     PPDMDEVINSR0                 pDevInsR0;                           /**< Device instance - R0. */
    143     PPDMDEVINSRC                 pDevInsRC;                           /**< Device instance - RC. */
    144 
    145 
    146     uint8_t                      uPciCfgDataOff;
    147 #if HC_ARCH_BITS == 64
    148     uint32_t                     padding2;
    149 #endif
    150 
    151     /** Base port of I/O space region. */
    152     RTIOPORT                     IOPortBase;
    153 
    154     uint32_t                     uGuestFeatures;
    155     uint16_t                     uQueueSelector;                      /** An index in aQueues array. */
    156     uint8_t                      uStatus;                             /** Device Status (bits are device-specific). */
    157     uint8_t                      uISR;                                /** Interrupt Status Register. */
    158 
    159 #if HC_ARCH_BITS != 64
    160     uint32_t                     padding3;
    161 #endif
    162 
    163     VQUEUE                       Queues[VIRTIO_MAX_QUEUES];
    164     uint32_t                     uNotifyOffMultiplier;                /* Multiplier for uQueueNotifyOff[idx] */
    165 
    166     /** Whole virtio device */
    167     uint32_t                     uDeviceFeaturesSelect;               /** Select hi/lo 32-bit uDeviceFeatures to r/w */
    168     uint64_t                     uDeviceFeatures;                     /** Host features offered */
    169     uint32_t                     uDriverFeaturesSelect;               /** Selects hi/lo 32-bit uDriverFeatures to r/w*/
    170     uint64_t                     uDriverFeatures;                     /** Host features accepted by guest */
    171     uint32_t                     uMsixConfig;
    172     uint32_t                     uNumQueues;                          /** Actual number of queues used. */
    173     uint8_t                      uDeviceStatus;
    174     uint8_t                      uConfigGeneration;
    175 
    176     /** Specific virtqueue */
    177     uint16_t                     uQueueSelect;
    178     uint16_t                     uQueueSize[VIRTIO_MAX_QUEUES];       /** Device sets on reset, driver can modify */
    179     uint16_t                     uQueueNotifyOff[VIRTIO_MAX_QUEUES];  /** Device sets this */
    180     uint16_t                     uQueueMsixVector[VIRTIO_MAX_QUEUES]; /** Driver specifies queue vector for MSI-X */
    181     uint16_t                     uQueueEnable[VIRTIO_MAX_QUEUES];     /** Driver controls device access to queue */
    182     uint64_t                     uQueueDesc[VIRTIO_MAX_QUEUES];       /** Driver provides this */
    183     uint64_t                     uQueueAvail[VIRTIO_MAX_QUEUES];      /** Driver provides this */
    184     uint64_t                     uQueueUsed[VIRTIO_MAX_QUEUES];       /** Driver provides this */
    185 
    186 
    187     uint8_t                      uVirtioCapBar;                       /* Capabilities BAR (region) assigned by client */
    188 
    189     /** Callbacks when guest driver reads or writes VirtIO device-specific capabilities(s) */
    190     PFNPCICONFIGREAD             pfnPciConfigReadOld;
    191     PFNPCICONFIGWRITE            pfnPciConfigWriteOld;
    192 
    193     uint32_t                     cbDevSpecificCap;                    /* Size of client's dev-specific config data  */
    194     void                        *pDevSpecificCap;                     /* Pointer to client's struct                 */
    195     void                        *pPrevDevSpecificCap;                 /* Previous read dev-specific cfg of client */
    196     bool                         fGenUpdatePending;                   /* If set, update cfg gen. after driver reads */
    197 
    198     PVIRTIO_PCI_CFG_CAP_T        pPciCfgCap;                          /** Pointer to struct in configuration area */
    199     PVIRTIO_PCI_NOTIFY_CAP_T     pNotifyCap;                          /** Pointer to struct in configuration area */
    200     PVIRTIO_PCI_CAP_T            pCommonCfgCap;                       /** Pointer to struct in configuration area */
    201     PVIRTIO_PCI_CAP_T            pIsrCap;                             /** Pointer to struct in configuration area */
    202     PVIRTIO_PCI_CAP_T            pDeviceCap;                          /** Pointer to struct in configuration area */
    203 
    204     /** Base address of PCI capabilities */
    205     RTGCPHYS                     GCPhysPciCapBase;
    206     RTGCPHYS                     pGcPhysCommonCfg;                    /** Pointer to MMIO mapped capability data */
    207     RTGCPHYS                     pGcPhysNotifyCap;                    /** Pointer to MMIO mapped capability data */
    208     RTGCPHYS                     pGcPhysIsrCap;                       /** Pointer to MMIO mapped capability data */
    209     RTGCPHYS                     pGcPhysDeviceCap;                    /** Pointer to MMIO mapped capability data */
    210 
    211     bool fDeviceConfigInterrupt;
    212     bool fQueueInterrupt;
     143    PDMPCIDEV                 dev;                               /**< PCI device                                */
     144    char                      szInstance[16];                    /**< Instance name, e.g. "VIRTIOSCSI0"         */
     145
     146    PPDMDEVINSR3              pDevInsR3;                         /**< Device instance - R3                      */
     147    PPDMDEVINSR0              pDevInsR0;                         /**< Device instance - R0                      */
     148    PPDMDEVINSRC              pDevInsRC;                         /**< Device instance - RC                      */
     149
     150    RTGCPHYS                  pGcPhysPciCapBase;                 /**< Pointer to MMIO mapped capability data    */
     151    RTGCPHYS                  pGcPhysCommonCfg;                  /**< Pointer to MMIO mapped capability data    */
     152    RTGCPHYS                  pGcPhysNotifyCap;                  /**< Pointer to MMIO mapped capability data    */
     153    RTGCPHYS                  pGcPhysIsrCap;                     /**< Pointer to MMIO mapped capability data    */
     154    RTGCPHYS                  pGcPhysDeviceCap;                  /**< Pointer to MMIO mapped capability data    */
     155
     156    RTGCPHYS                  pGcPhysQueueDesc[VIRTQ_MAX_CNT];   /**< (MMIO) PhysAdr per-Q desc structs   GUEST */
     157    RTGCPHYS                  pGcPhysQueueAvail[VIRTQ_MAX_CNT];  /**< (MMIO) PhysAdr per-Q avail structs  GUEST */
     158    RTGCPHYS                  pGcPhysQueueUsed[VIRTQ_MAX_CNT];   /**< (MMIO) PhysAdr per-Q used structs   GUEST */
     159    uint16_t                  uQueueNotifyOff[VIRTQ_MAX_CNT];    /**< (MMIO) per-Q notify offset           HOST */
     160    uint16_t                  uQueueMsixVector[VIRTQ_MAX_CNT];   /**< (MMIO) Per-queue vector for MSI-X   GUEST */
     161    uint16_t                  uQueueEnable[VIRTQ_MAX_CNT];       /**< (MMIO) Per-queue enable             GUEST */
     162    uint16_t                  uQueueSize[VIRTQ_MAX_CNT];         /**< (MMIO) Per-queue size          HOST/GUEST */
     163    uint16_t                  uQueueSelect;                      /**< (MMIO) queue selector               GUEST */
     164    uint16_t                  padding;
     165    uint64_t                  uDeviceFeatures;                   /**< (MMIO) Host features offered         HOST */
     166    uint64_t                  uDriverFeatures;                   /**< (MMIO) Host features accepted       GUEST */
     167    uint32_t                  uDeviceFeaturesSelect;             /**< (MMIO) hi/lo select uDeviceFeatures GUEST */
     168    uint32_t                  uDriverFeaturesSelect;             /**< (MMIO) hi/lo select uDriverFeatures GUEST */
     169    uint32_t                  uMsixConfig;                       /**< (MMIO) MSI-X vector                 GUEST */
     170    uint32_t                  uNumQueues;                        /**< (MMIO) Actual number of queues      GUEST */
     171    uint8_t                   uDeviceStatus;                     /**< (MMIO) Device Status                GUEST */
     172    uint8_t                   uConfigGeneration;                 /**< (MMIO) Device config sequencer       HOST */
     173
     174    VIRTQ_CONTEXT_T           queueContext[VIRTQ_MAX_CNT];       /**< Local impl-specific queue context         */
     175    VIRTIOCALLBACKS           virtioCallbacks;                   /**< Callback vectors to client                */
     176
     177    PFNPCICONFIGREAD          pfnPciConfigReadOld;               /**< Prev rd. cb. intercepting PCI Cfg I/O     */
     178    PFNPCICONFIGWRITE         pfnPciConfigWriteOld;              /**< Prev wr. cb. intercepting PCI Cfg I/O     */
     179
     180    PVIRTIO_PCI_CFG_CAP_T     pPciCfgCap;                        /**< Pointer to struct in configuration area   */
     181    PVIRTIO_PCI_NOTIFY_CAP_T  pNotifyCap;                        /**< Pointer to struct in configuration area   */
     182    PVIRTIO_PCI_CAP_T         pCommonCfgCap;                     /**< Pointer to struct in configuration area   */
     183    PVIRTIO_PCI_CAP_T         pIsrCap;                           /**< Pointer to struct in configuration area   */
     184    PVIRTIO_PCI_CAP_T         pDeviceCap;                        /**< Pointer to struct in configuration area   */
     185
     186    uint32_t                  cbDevSpecificCap;                  /**< Size of client's dev-specific config data */
     187    void                     *pDevSpecificCap;                   /**< Pointer to client's struct                */
     188    void                     *pPrevDevSpecificCap;               /**< Previous read dev-specific cfg of client  */
     189    bool                      fGenUpdatePending;                 /**< If set, update cfg gen after driver reads */
     190    uint8_t                   uPciCfgDataOff;
     191    uint8_t                   uVirtioCapBar;                     /**< Capabilities BAR/region (client-assigned) */
     192    uint8_t                   uISR;                              /**< Interrupt Status Register.                */
    213193
    214194} VIRTIOSTATE, *PVIRTIOSTATE;
    215195
    216 DECLINLINE(uint16_t) vringReadAvail(PVIRTIOSTATE pVirtio, PVIRTQ pVirtQ)
    217 {
    218     uint16_t dataWord;
    219     PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
    220                       pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
    221                       &dataWord, sizeof(dataWord));
    222     return dataWord;
    223 }
    224 
    225 DECLINLINE(bool) virtQueuePeek(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem)
    226 {
    227     return virtQueueGet(pVirtio, pQueue, pElem, /* fRemove */ false);
    228 }
    229 
    230 DECLINLINE(bool) virtQueueIsReady(PVIRTIOSTATE pVirtio, PVQUEUE pQueue)
    231 {
    232     NOREF(pVirtio);
    233     return !!pQueue->VirtQ.pGcPhysVirtqAvail;
    234 }
    235 
    236 DECLINLINE(bool) virtQueueIsEmpty(PVIRTIOSTATE pVirtio, PVQUEUE pQueue)
    237 {
    238     return (vringReadAvail(pVirtio, &pQueue->VirtQ) == pQueue->uNextAvailIndex);
    239 }
     196/** virtq related flags */
     197#define VIRTQ_DESC_F_NEXT                               1        /**< Indicates this descriptor chains to next  */
     198#define VIRTQ_DESC_F_WRITE                              2        /**< Marks buffer as write-only (default ro)   */
     199#define VIRTQ_DESC_F_INDIRECT                           4        /**< Buffer is list of buffer descriptors      */
     200
     201#define VIRTQ_USED_F_NO_NOTIFY                          1        /**< Dev to Drv: Don't notify when buf added   */
     202#define VIRTQ_AVAIL_F_NO_INTERRUPT                      1        /**< Drv to Dev: Don't notify when buf eaten   */
     203
     204/**
     205 * virtq related structs
     206 * (struct names follow VirtIO 1.0 spec, typedef use VBox style)
     207 */
     208typedef struct virtq_desc
     209{
     210    uint64_t  pGcPhysBuf;                                        /**< addr       GC Phys. address of buffer     */
     211    uint32_t  cb;                                                /**< len        Buffer length                  */
     212    uint16_t  fFlags;                                            /**< flags      Buffer specific flags          */
     213    uint16_t  uDescIdxNext;                                      /**< next       Idx set if VIRTIO_DESC_F_NEXT  */
     214} VIRTQ_DESC_T, *PVIRTQ_DESC_T;
     215
     216typedef struct virtq_avail
     217{
     218    uint16_t  fFlags;                                            /**< flags      avail ring drv to dev flags    */
     219    uint16_t  uDescIdx;                                          /**< idx        Index of next free ring slot   */
     220    uint16_t  auRing[1];                                         /**< ring       Ring: avail drv to dev bufs    */
     221    uint16_t  uUsedEventIdx;                                     /**< used_event (if VIRTQ_USED_F_NO_NOTIFY)    */
     222} VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
     223
     224typedef struct virtq_used_elem
     225{
     226    uint32_t  uDescIdx;                                          /**< idx         Start of used desc chain      */
     227    uint32_t  cbElem;                                            /**< len         Total len of used desc chain  */
     228} VIRTQ_USED_ELEM_T;
     229
     230typedef struct virt_used
     231{
     232    uint16_t  fFlags;                                            /**< flags       used ring host-to-guest flags */
     233    uint16_t  uDescIdx;                                          /**< idx         Index of next ring slot       */
     234    VIRTQ_USED_ELEM_T auRing[1];                                 /**< ring        Ring: used dev to drv bufs    */
     235    uint16_t  uAvailEventIdx;                                    /**< avail_event if (VIRTQ_USED_F_NO_NOTIFY)   */
     236} VIRTQ_USED_T, *PVIRTQ_USED_T;
     237
    240238/**
    241239* This macro returns true if physical address and access length are within the mapped capability struct.
     
    249247*     @param    GCPhysAddr     - [input, implied] Physical address accessed (via MMIO callback)
    250248*     @param    cb             - [input, implied] Number of bytes to access
    251 *
    252249*/
    253250#define MATCH_VIRTIO_CAP_STRUCT(pGcPhysCapData, pCfgCap, fMatched) \
     
    268265 * @result           - true or false
    269266 */
    270 #define COMMON_CFG(member) \
     267#define MATCH_COMMON_CFG(member) \
    271268        (RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member) == 8 \
    272269         && (   uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \
     
    276273           && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member))
    277274
    278 #define LOG_ACCESSOR(member) \
    279         virtioLogMappedIoValue(__FUNCTION__, #member, pv, cb, uIntraOff, fWrite, false, 0);
    280 
    281 #define LOG_INDEXED_ACCESSOR(member, idx) \
    282         virtioLogMappedIoValue(__FUNCTION__, #member, pv, cb, uIntraOff, fWrite, true, idx);
    283 
    284 #define ACCESSOR(member) \
     275#define LOG_COMMON_CFG_ACCESS(member) \
     276        virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
     277                                pv, cb, uIntraOff, fWrite, false, 0);
     278
     279#define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx) \
     280        virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \
     281                               pv, cb, uIntraOff, fWrite, true, idx);
     282
     283#define COMMON_CFG_ACCESSOR(member) \
    285284    { \
    286285        uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     
    289288        else \
    290289            memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
    291         LOG_ACCESSOR(member); \
     290        LOG_COMMON_CFG_ACCESS(member); \
    292291    }
    293292
    294 #define ACCESSOR_WITH_IDX(member, idx) \
     293#define COMMON_CFG_ACCESSOR_INDEXED(member, idx) \
    295294    { \
    296295        uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     
    299298        else \
    300299            memcpy((char *)pv, (const char *)(((char *)(pVirtio->member + idx)) + uIntraOff), cb); \
    301         LOG_INDEXED_ACCESSOR(member, idx); \
     300        LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
    302301    }
    303302
    304 #define ACCESSOR_READONLY(member) \
     303#define COMMON_CFG_ACCESSOR_READONLY(member) \
    305304    { \
    306305        uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     
    310309        { \
    311310            memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \
    312             LOG_ACCESSOR(member); \
     311            LOG_COMMON_CFG_ACCESS(member); \
    313312        } \
    314313    }
    315314
    316 #define ACCESSOR_READONLY_WITH_IDX(member, idx) \
     315#define COMMON_CFG_ACCESSOR_INDEXED_READONLY(member, idx) \
    317316    { \
    318317        uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \
     
    321320        else \
    322321        { \
    323             memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + uOffset, cb); \
    324             LOG_INDEXED_ACCESSOR(member, idx); \
     322            memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + uIntraOff, cb); \
     323            LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \
    325324        } \
    326325    }
    327326
    328 #ifdef VBOX_DEVICE_STRUCT_TESTCASE
    329 #  define virtioDumpState(x, s)  do {} while (0)
    330 #else
    331 #  ifdef DEBUG
    332         static void virtioDumpState(PVIRTIOSTATE pVirtio, const char *pcszCaller)
    333         {
    334             RT_NOREF2(pVirtio, pcszCaller);
    335             /* PK TODO, dump state features, selector, status, ISR, queue info (iterate),
    336                         descriptors, avail, used, size, indices, address
    337                         each by variable name on new line, indented slightly */
    338         }
    339 #  endif
    340 #endif
    341 
     327/**
     328 * Internal queue operations
     329 */
     330
     331static int         vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
     332static bool        vqIsEmpty              (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     333static void        vqReset                (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     334static void        vqReadDesc             (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc);
     335static uint16_t    vqReadAvailRingDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx);
     336static uint16_t    vqReadAvailDescIdx     (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     337static uint16_t    vqReadAvailFlags       (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     338static uint16_t    vqReadAvailUsedEvent   (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     339static void        vqWriteUsedElem        (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen);
     340static void        vqWriteUsedRingDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uDescIdx);
     341static uint16_t    vqReadUsedDescIdx      (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     342static uint16_t    vqReadUsedFlags        (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     343static void        vqWriteUsedFlags       (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags);
     344static uint16_t    vqReadUsedAvailEvent   (PVIRTIOSTATE pVirtio, uint16_t qIdx);
     345static void        vqWriteUsedAvailEvent  (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx);
     346
     347DECLINLINE(int) vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld)
     348{
     349    return (uint16_t)(uDescIdxNew - uEventIdx - 1) < (uint16_t)(uDescIdxNew - uDescIdxOld);
     350}
     351
     352DECLINLINE(bool) vqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     353{
     354    return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->queueContext->uNextAvailIdx;
     355}
     356
     357/**
     358 * Accessor for virtq descspVirtio
     359 */
     360DECLINLINE(void) vqReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc)
     361{
     362    //Log(("%s virtioQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx));
     363    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     364                      pVirtio->pGcPhysQueueDesc[qIdx]
     365                         + sizeof(VIRTQ_DESC_T) * (uDescIdx % pVirtio->uQueueSize[qIdx]),
     366                      pDesc, sizeof(VIRTQ_DESC_T));
     367}
     368
     369/**
     370 * Accessors for virtq avail ring
     371 */
     372DECLINLINE(uint16_t) vqReadAvailRingDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx)
     373{
     374    uint16_t uDescIdx;
     375    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     376                      pVirtio->pGcPhysQueueAvail[qIdx]
     377                         + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % pVirtio->uQueueSize[qIdx]]),
     378                      &uDescIdx, sizeof(uDescIdx));
     379    return uDescIdx;
     380}
     381
     382DECLINLINE(uint16_t) vqReadAvailDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     383{
     384    uint16_t uDescIdx;
     385    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     386                      pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uDescIdx),
     387                      &uDescIdx, sizeof(uDescIdx));
     388    return uDescIdx;
     389}
     390
     391DECLINLINE(uint16_t) vqReadAvailFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     392{
     393    uint16_t fFlags;
     394    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     395                      pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
     396                      &fFlags, sizeof(fFlags));
     397    return fFlags;
     398}
     399
     400DECLINLINE(uint16_t) vqReadAvailUsedEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     401{
     402    uint16_t uUsedEventIdx;
     403    /** VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */
     404    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     405                      + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uQueueSize[qIdx]]),
     406                      &uUsedEventIdx, sizeof(uUsedEventIdx));
     407    return uUsedEventIdx;
     408}
     409
     410/**
     411 * Accessors for virtq used ring
     412 */
     413DECLINLINE(void) vqWriteUsedElem(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen)
     414{
     415    VIRTQ_USED_ELEM_T elem = { uDescIdx,  uLen };
     416    PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
     417                          pVirtio->pGcPhysQueueUsed[qIdx]
     418                            + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[usedIdx % pVirtio->uQueueSize[qIdx]]),
     419                          &elem, sizeof(elem));
     420}
     421
     422DECLINLINE(void) vqWriteUsedRingDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uDescIdx)
     423{
     424    PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
     425                          pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uDescIdx),
     426                          &uDescIdx, sizeof(uDescIdx));
     427}
     428
     429DECLINLINE(uint16_t)vqReadUsedDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     430{
     431    uint16_t uDescIdx;
     432    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     433                      pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uDescIdx),
     434                      &uDescIdx, sizeof(uDescIdx));
     435    return uDescIdx;
     436}
     437
     438DECLINLINE(uint16_t) vqReadUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     439{
     440    uint16_t fFlags;
     441    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     442                      pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
     443                      &fFlags, sizeof(fFlags));
     444    return fFlags;
     445}
     446
     447DECLINLINE(void) vqWriteUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags)
     448{
     449    PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
     450                          pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
     451                          &fFlags, sizeof(fFlags));
     452}
     453
     454DECLINLINE(uint16_t) vqReadUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     455{
     456    uint16_t uAvailEventIdx;
     457    /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
     458    PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns),
     459                    + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[pVirtio->uQueueSize[qIdx]]),
     460                      &uAvailEventIdx, sizeof(uAvailEventIdx));
     461    return uAvailEventIdx;
     462}
     463
     464DECLINLINE(void) vqWriteUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx)
     465{
     466    /** VirtIO 1.0 uAvailEventIdx (avail event) immediately follows ring */
     467    PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
     468                          pVirtio->pGcPhysQueueUsed[qIdx]
     469                            + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[pVirtio->uQueueSize[qIdx]]),
     470                          &uAvailEventIdx, sizeof(uAvailEventIdx));
     471}
     472
     473/**
     474 * Makes the MMIO-mapped Virtio uDeviceStatus registers non-cryptic */
    342475DECLINLINE(void) virtioLogDeviceStatus( uint8_t status)
    343476{
     
    358491            Log(("%sFAILED",      primed++ ? " | " : ""));
    359492        if (status & VIRTIO_STATUS_DEVICE_NEEDS_RESET)
    360             Log(("%sACKNOWLEDGE", primed++ ? " | " : ""));
     493            Log(("%sNEEDS_RESET", primed++ ? " | " : ""));
    361494    }
    362495}
    363496
    364 /*  FROM Virtio 1.0 SPEC, NYI
    365       static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx)
    366             return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx);
    367       }
    368       // Get location of event indices (only with VIRTIO_F_EVENT_IDX)
    369       static inline le16 *virtq_used_event(struct virtq *vq)
    370       {
    371               // For backwards compat, used event index is at *end* of avail ring.
    372               return &vq->avail->ring[vq->num];
    373 }
    374       static inline le16 *virtq_avail_event(struct virtq *vq)
    375       {
    376               // For backwards compat, avail event index is at *end* of used ring.
    377               return (le16 *)&vq->used->ring[vq->num];
    378       }
    379 }
    380 */
    381 void    virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
    382 void   *virtioQueryInterface(struct PDMIBASE *pInterface, const char *pszIID);
    383 int     virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM);
    384 int     virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t uNumQueues);
     497void   vqNotified(PVIRTIOSTATE pVirtio, uint32_t qidx, uint16_t uDescIdx);
     498static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause);
     499
     500//void    virtioNotifyDriver(     VIRTIOHANDLE hVirtio);
     501//void    virtQueueNotify(        VIRTIOHANDLE hVirtio, PVQUEUE pQueue);
     502//void    vringSetNotification(   VIRTIOHANDLE hVirtio, PVIRTQ pVirtQ, bool fEnabled);
     503
     504static DECLCALLBACK(int) virtioR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
     505static DECLCALLBACK(int) virtioR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
     506static DECLCALLBACK(int) virtioR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
     507static DECLCALLBACK(int) virtioR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass);
    385508
    386509#endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h */
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