VirtualBox

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


Ignore:
Timestamp:
Aug 19, 2019 7:43:37 AM (5 years ago)
Author:
vboxsync
Message:

Fixed error in MMIO handling of cfg gen check/increment. Seem to have resolved stack corruption issue caused by putting structs that allocated 1.5MB on the stack in temporary functions to test notification callback and test de-queing data. See bugref:9440 Comment #53 for more info

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

Legend:

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

    r80308 r80340  
    3535
    3636#ifdef LOG_ENABLED
    37 # define QUEUENAME(s, q) (q->pcszName)
     37# define QUEUENAME(s, q) (q->szName)
    3838#endif
    3939
     
    9393}
    9494
    95 
    96 /**
    97  * The queue layout is defined in VirtIO 1.0 spec according to VirtIO device type.
    98  * The guest driver is responsible for creating the queues and conveying the
    99  * queue location to the device. When the driver reaches "DRIVER OK" state,
    100  * the client should call this function to give the queue an implementation-specific
    101  * name and a create its shadow context, for example, to track and manage lag in reading
    102  * incoming or pre-loading outgoing.
    103  */
    104 bool virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName)
    105 {
     95int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName)
     96{
     97    LogFunc(("%s\n", pcszName));
    10698    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    107     PVIRTQ_SHADOW_T pVirtqShadow = &(pVirtio->virtqShadow[qIdx]);
     99    PVIRTQ_PROXY_T pVirtqProxy = &(pVirtio->virtqProxy[qIdx]);
    108100    if (pVirtio->uQueueEnable[qIdx])
    109101    {
    110         Log2Func(("Queue name: %-16s\n", pcszName));
    111         pVirtqShadow->uAvailIdx = 0;
    112         pVirtqShadow->uUsedIdx  = 0;
    113         pVirtqShadow->fEventThresholdReached = false;
    114         RTStrCopy((char *)pVirtqShadow->pcszName, sizeof(pVirtqShadow->pcszName), pcszName);
    115         return true;
    116     }
    117     return false;
     102        pVirtqProxy->pBufVec = (PVIRTQ_BUF_VECTOR_T)RTMemAllocZ(sizeof(PVIRTQ_BUF_VECTOR_T));
     103        if (!pVirtqProxy->pBufVec)
     104        {
     105            Log(("Out of memory!"));
     106            return VERR_NO_MEMORY;
     107        }
     108        pVirtqProxy->uAvailIdx = 0;
     109        pVirtqProxy->uUsedIdx  = 0;
     110        pVirtqProxy->fEventThresholdReached = false;
     111        RTStrCopy((char *)pVirtqProxy->szName, sizeof(pVirtqProxy->szName), pcszName);
     112        return VINF_SUCCESS;
     113    }
     114    LogFunc(("Couldn't attach to %s: Not enabled\n", pcszName));
     115    return VERR_INVALID_STATE;
     116}
     117
     118PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     119{
     120    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     121    if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
     122    {
     123        PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     124        return pVirtqProxy->pBufVec;
     125    }
     126    LogFunc(("Can't get buffer, driver not ready\n"));
     127    return NULL;
    118128}
    119129
    120130const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    121131{
    122     return (const char *)((PVIRTIOSTATE)hVirtio)->virtqShadow[qIdx].pcszName;
    123 }
    124 
    125 
    126 bool virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    127 {
    128132    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    129     PVIRTQ_SHADOW_T pVirtqShadow = &pVirtio->virtqShadow[qIdx];
     133    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     134                    ("Guest driver not in ready state.\n"), "<null>");
     135
     136    return (const char *)((PVIRTIOSTATE)hVirtio)->virtqProxy[qIdx].szName;
     137}
     138
     139int virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     140{
     141    Assert(qIdx < sizeof(VIRTQ_PROXY_T));
     142
     143    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     144    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     145
     146    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     147                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    130148
    131149    if (virtioQueueIsEmpty(pVirtio, qIdx))
    132         return false;
     150        return VERR_NOT_AVAILABLE;
    133151
    134152    Log2Func(("%s: %s avail_idx=%u\n", INSTANCE(pVirtio),
    135           pVirtqShadow->pcszName, pVirtqShadow->uAvailIdx));
    136     pVirtqShadow->uAvailIdx++;
    137     return true;
     153          pVirtqProxy->szName, pVirtqProxy->uAvailIdx));
     154    pVirtqProxy->uAvailIdx++;
     155
     156    return VINF_SUCCESS;
    138157}
    139158
     
    141160{
    142161    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    143     return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->virtqShadow->uAvailIdx;
    144 }
    145 
    146 bool virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec)
    147 {
    148     return virtioQueueGet(hVirtio, qIdx, pBufVec, /* fRemove */ false);
    149 }
    150 
    151 /**
    152  * Removes one descriptor chain from the avail ring of the specified virtq and converts
    153  * it to an easily consumable scatter/gather buffer vector and returns it to the caller.
    154  */
    155 bool virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, bool fRemove)
    156 {
    157 
     162    return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->virtqProxy->uAvailIdx;
     163}
     164
     165int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     166{
     167    return virtioQueueGet(hVirtio, qIdx, false /* fRemove */);
     168}
     169
     170 /** See API comments in header file prototype for description */
     171int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove)
     172{
    158173    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    159     PVIRTQ_SHADOW_T pVirtqShadow = &pVirtio->virtqShadow[qIdx];
    160 
    161     if (!(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK))
    162     {
    163         LogFlowFunc(("Guest driver not in ready state. Can't consume buffers. Ignoring\n"));
    164         return false;
    165     }
     174    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     175    PVIRTQ_BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;
     176
     177    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     178                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    166179
    167180    if (vqIsEmpty(pVirtio, qIdx))
    168         return false;
     181        return VERR_NOT_AVAILABLE;
    169182
    170183    pBufVec->cSegsIn = pBufVec->cSegsOut = 0;
    171184
    172     Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pVirtqShadow->pcszName, pVirtqShadow->uAvailIdx));
     185    Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pVirtqProxy->szName, pVirtqProxy->uAvailIdx));
    173186
    174187    uint16_t uDescIdx;
    175     pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqShadow->uAvailIdx);
     188//    pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx);
    176189
    177190    if (fRemove)
    178         pVirtqShadow->uAvailIdx++;
     191        pVirtqProxy->uAvailIdx++;
    179192
    180193    VIRTQ_DESC_T desc;
     
    187200        * several descriptors into a loop. Since there is no legitimate way to get a sequences of
    188201        * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}),
    189         * the following aborts I/O if breech and employs a simple log throttling algorithm to notify.
     202        * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
    190203        */
    191204        if (pBufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE)
     
    207220        RT_UNTRUSTED_VALIDATED_FENCE();
    208221
    209         vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
     222//        vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
    210223        if (desc.fFlags & VIRTQ_DESC_F_WRITE)
    211224        {
    212225            Log2Func(("%s: %s IN  seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),
    213                   pVirtqShadow->pcszName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb));
     226                  pVirtqProxy->szName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb));
    214227            pSeg = &(pBufVec->aSegsIn[pBufVec->cSegsIn++]);
    215228        }
     
    217230        {
    218231            Log2Func(("%s: %s IN  seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),
    219                   pVirtqShadow->pcszName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb));
     232                  pVirtqProxy->szName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb));
    220233            pSeg = &(pBufVec->aSegsOut[pBufVec->cSegsOut++]);
    221234        }
     
    229242
    230243    Log2Func(("%s: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pVirtio),
    231           pVirtqShadow->pcszName, pBufVec->uDescIdx, pBufVec->cSegsIn, pBufVec->cSegsOut));
    232 
    233     return true;
    234 }
    235 
    236 /**
    237  * Puts a scatter gather buffer vector on the used ring of the specified virtq.
    238  * This function does *not* update the index of the physical ring buffer, nor does it
    239  * notify the guest driver. That happens when virtioQueueSync() is subsequently called,
    240  * allows for multiple entries to be queued up before transferring to the guest driver.
    241  */
    242 void virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, uint32_t cb)
    243 {
     244          pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn, pBufVec->cSegsOut));
     245
     246    return VINF_SUCCESS;
     247}
     248
     249 /** See API comments in header file prototype for description */
     250int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     251{
     252    Assert(qIdx < sizeof(VIRTQ_PROXY_T));
     253
    244254    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    245     PVIRTQ_SHADOW_T pVirtqShadow = &pVirtio->virtqShadow[qIdx];
     255    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     256    PVIRTQ_BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;
     257
     258    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     259                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    246260
    247261    Log2Func(("%s: %s desc_idx=%u acb=%u\n",
    248              INSTANCE(pVirtio), pVirtqShadow->pcszName, pBufVec->uDescIdx, cb));
    249 
    250     uint32_t cbRemaining = cb;
     262             INSTANCE(pVirtio), pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn));
     263
     264    uint32_t cbRemaining = pBufVec->cSegsIn;
    251265
    252266    for (uint32_t iSeg = 0; iSeg < pBufVec->cSegsIn && cbRemaining > 0; ++iSeg)
     
    256270            cbSegLen = cbRemaining;
    257271
    258         Assert(pBufVec->aSegsIn[iSeg].pv != NULL);
    259272
    260273        if (pBufVec->aSegsIn[iSeg].pv != NULL)
    261274        {
    262275            Log2Func(("%s: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n",
    263                      INSTANCE(pVirtio), pVirtqShadow->pcszName,
    264                      pVirtqShadow->uUsedIdx, iSeg,
     276                     INSTANCE(pVirtio), pVirtqProxy->szName,
     277                     pVirtqProxy->uUsedIdx, iSeg,
    265278                     (void *)pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv,
    266279                     pBufVec->aSegsIn[iSeg].cb, cbSegLen));
     
    274287    uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
    275288    Log2Func(("%s: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n",
    276           INSTANCE(pVirtio), pVirtqShadow->pcszName,
    277           pVirtqShadow->uUsedIdx, uDescIdx, pBufVec->uDescIdx, cb));
    278 
    279     if (pVirtqShadow->uUsedIdx == vqReadAvailUsedEvent(pVirtio, qIdx))
    280         pVirtqShadow->fEventThresholdReached = true;
    281     vqWriteUsedElem(pVirtio, qIdx, pVirtqShadow->uUsedIdx++, pBufVec->uDescIdx, cb);
    282 }
    283 
    284 /**
    285  * Updates the specified virtq's used ring buffer's index, making it reflect the current
    286  * number of additional entries added to the queue, and notifies the guest driver.
    287  */
    288 void virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx)
    289 {
     289          INSTANCE(pVirtio), pVirtqProxy->szName,
     290          pVirtqProxy->uUsedIdx, uDescIdx, pBufVec->uDescIdx, pBufVec->cSegsIn));
     291
     292    if (pVirtqProxy->uUsedIdx == vqReadAvailUsedEvent(pVirtio, qIdx))
     293        pVirtqProxy->fEventThresholdReached = true;
     294    vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, pBufVec->uDescIdx,  pBufVec->cSegsIn);
     295
     296    return VINF_SUCCESS;
     297}
     298
     299 /** See API comments in header file prototype for description */
     300int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx)
     301{
     302    Assert(qIdx < sizeof(VIRTQ_PROXY_T));
     303
    290304    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    291     PVIRTQ_SHADOW_T pVirtqShadow = &pVirtio->virtqShadow[qIdx];
     305    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     306
     307    AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     308                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    292309
    293310    uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
    294311    Log2Func(("%s: %s old_used_idx=%u new_used_idx=%u\n",
    295               INSTANCE(pVirtio), uDescIdx, pVirtqShadow->uUsedIdx));
    296 
    297     vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtqShadow->uUsedIdx);
     312              INSTANCE(pVirtio), uDescIdx, pVirtqProxy->uUsedIdx));
     313
     314    vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx);
    298315    vqNotifyDriver(pVirtio, qIdx);
    299 }
    300 
    301 /**
    302  * This is called when MMIO handler detects guest write to a virtq's notification address
    303  */
    304 static void vqDeviceNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx)
     316
     317    return VINF_SUCCESS;
     318}
     319
     320 /** See API comments in header file prototype for description */
     321static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx)
    305322{
    306323    Assert(uNotifyIdx == qIdx);
    307     PVIRTQ_SHADOW_T pVirtqShadow = &pVirtio->virtqShadow[qIdx];
    308     Log2Func(("%s: %s notified\n", INSTANCE(pVirtio), pVirtqShadow->pcszName));
     324
     325    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     326    Log2Func(("%s: %s notified\n", INSTANCE(pVirtio), pVirtqProxy->szName));
    309327
    310328    /** Inform client */
    311     pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, qIdx);
     329    pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, pVirtio->pClientContext, qIdx);
    312330}
    313331
     
    316334 * the specified virtq, depending on the interrupt configuration of the device
    317335 * and depending on negotiated and realtime constraints flagged by the guest driver.
    318  * See VirtIO 1.0 specification (see section 2.4.7).
     336 * See VirtIO 1.0 specification (section 2.4.7).
    319337 */
    320338static void vqNotifyDriver(PVIRTIOSTATE pVirtio, uint16_t qIdx)
    321339{
    322     PVIRTQ_SHADOW_T pVirtqShadow = &pVirtio->virtqShadow[qIdx];
    323 
    324     if (!(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK))
    325     {
    326         LogFlowFunc(("Guest driver not in ready state. Ignoring notify request\n"));
    327         return;
    328     }
     340    PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
     341
     342    AssertMsgReturnVoid(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
     343                    ("Guest driver not in ready state.\n"));
    329344
    330345    LogFlowFunc(("%s: %s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n",
    331         INSTANCE(pVirtio), pVirtqShadow->pcszName, vqReadAvailFlags(pVirtio, qIdx),
     346        INSTANCE(pVirtio), pVirtqProxy->szName, vqReadAvailFlags(pVirtio, qIdx),
    332347            pVirtio->uDriverFeatures, vqIsEmpty(pVirtio, qIdx) ? "" : "not "));
    333348
     
    335350    {
    336351        if (   pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX
    337             && pVirtqShadow->fEventThresholdReached)
     352            && pVirtqProxy->fEventThresholdReached)
    338353        {
    339354                virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT);
    340                 pVirtqShadow->fEventThresholdReached = false;
     355                pVirtqProxy->fEventThresholdReached = false;
    341356        }
    342357        else
    343358        {
     359            /** If guest driver hasn't suppressed interrupts, do so */
    344360            if (!(vqReadUsedFlags(pVirtio, qIdx) & VIRTQ_AVAIL_F_NO_INTERRUPT))
    345361                virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT);
     
    353369
    354370/**
    355  *
    356371 * NOTE: The consumer (PDM device) must call this function to 'forward' a relocation call.
    357372 *
    358373 * Device relocation callback.
    359  *
    360374 *
    361375 * When this callback is called the device instance data, and if the
     
    413427}
    414428
    415 
    416 
    417 static void vqReset(PVIRTIOSTATE pVirtio, uint16_t qIdx)
    418 {
    419     PVIRTQ_SHADOW_T pVirtQ = &pVirtio->virtqShadow[qIdx];
     429static void virtioResetQueue(PVIRTIOSTATE pVirtio, uint16_t qIdx)
     430{
     431    PVIRTQ_PROXY_T pVirtQ = &pVirtio->virtqProxy[qIdx];
    420432    pVirtQ->uAvailIdx = 0;
    421433    pVirtQ->uUsedIdx  = 0;
     
    442454    pVirtio->uNumQueues = VIRTQ_MAX_CNT;
    443455    for (uint16_t qIdx = 0; qIdx < pVirtio->uNumQueues; qIdx++)
    444         vqReset(pVirtio, qIdx);
     456        virtioResetQueue(pVirtio, qIdx);
    445457}
    446458
     
    451463void virtioResetAll(VIRTIOHANDLE hVirtio)
    452464{
     465    LogFunc(("VIRTIO RESET REQUESTED!!!\n"));
    453466    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
    454467    pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
     
    469482
    470483    /** Let the client know */
    471     pVirtio->virtioCallbacks.pfnVirtioStatusChanged((VIRTIOHANDLE)pVirtio, false);
     484    pVirtio->virtioCallbacks.pfnVirtioStatusChanged((VIRTIOHANDLE)pVirtio, pVirtio->pClientContext, false);
    472485    virtioResetDevice(pVirtio);
    473486}
     
    490503    {
    491504        if (fWrite) /* Guest WRITE pCommonCfg>uDeviceFeatures */
    492             Log(("Guest attempted to write readonly virtio_pci_common_cfg.device_feature\n"));
     505            LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.device_feature\n"));
    493506        else /* Guest READ pCommonCfg->uDeviceFeatures */
    494507        {
     
    508521                    break;
    509522                default:
    510                     Log2Func(("Guest read uDeviceFeatures with out of range selector (%d), returning 0\n",
     523                    LogFunc(("Guest read uDeviceFeatures with out of range selector (%d), returning 0\n",
    511524                          pVirtio->uDeviceFeaturesSelect));
    512525                    return VERR_ACCESS_DENIED;
     
    531544                    break;
    532545                default:
    533                     Log2Func(("Guest wrote uDriverFeatures with out of range selector (%d), returning 0\n",
     546                    LogFunc(("Guest wrote uDriverFeatures with out of range selector (%d), returning 0\n",
    534547                         pVirtio->uDriverFeaturesSelect));
    535548                    return VERR_ACCESS_DENIED;
     
    553566                    break;
    554567                default:
    555                     Log2Func(("Guest read uDriverFeatures with out of range selector (%d), returning 0\n",
     568                    LogFunc(("Guest read uDriverFeatures with out of range selector (%d), returning 0\n",
    556569                         pVirtio->uDriverFeaturesSelect));
    557570                    return VERR_ACCESS_DENIED;
     
    589602            bool fWasOkay = pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
    590603            if ((fOkayNow && !fWasOkay) || (!fOkayNow && fWasOkay))
    591                 pVirtio->virtioCallbacks.pfnVirtioStatusChanged(
    592                        (VIRTIOHANDLE)pVirtio, pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
     604                pVirtio->virtioCallbacks.pfnVirtioStatusChanged((VIRTIOHANDLE)pVirtio, pVirtio->pClientContext,
     605                       pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
    593606            pVirtio->uPrevDeviceStatus = pVirtio->uDeviceStatus;
    594607        }
     
    677690    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap,     fDevSpecific);
    678691    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysCommonCfg, pVirtio->pCommonCfgCap,  fCommonCfg);
    679     MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap,    pVirtio->pIsrCap,        fIsrCap);
     692    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap,    pVirtio->pIsrCap,        fIsr);
    680693
    681694    if (fDevSpecific)
    682695    {
    683         uint32_t uDevSpecificDataOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap;
     696        uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap;
    684697        /**
    685          * Callback to client to manage device-specific configuration and changes to it.
     698         * Callback to client to manage device-specific configuration.
    686699         */
    687         rc = pVirtio->virtioCallbacks.pfnVirtioDevCapRead(pDevIns, uDevSpecificDataOffset, pv, cb);
     700        rc = pVirtio->virtioCallbacks.pfnVirtioDevCapRead(pDevIns, uOffset, pv, cb);
     701
    688702        /**
    689          * Anytime any part of the device-specific configuration (which our client maintains) is read
    690          * it needs to be checked to see if it changed since the last time any part was read, in
     703         * Additionally, anytime any part of the device-specific configuration (which our client maintains)
     704         * is READ it needs to be checked to see if it changed since the last time any part was read, in
    691705         * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1)
    692706         */
    693         uint32_t fDevSpecificFieldChanged = false;
    694 
    695         if (memcmp((char *)pv + uDevSpecificDataOffset,
    696                    (char *)pVirtio->pPrevDevSpecificCap + uDevSpecificDataOffset, cb))
    697                              fDevSpecificFieldChanged = true;
    698 
    699         memcpy(pVirtio->pPrevDevSpecificCap, pv, pVirtio->cbDevSpecificCap);
     707        bool fDevSpecificFieldChanged = !!memcmp((char *)pVirtio->pDevSpecificCfg + uOffset,
     708                   (char *)pVirtio->pPrevDevSpecificCfg + uOffset, cb);
     709
     710        memcpy(pVirtio->pPrevDevSpecificCfg, pVirtio->pDevSpecificCfg, pVirtio->cbDevSpecificCfg);
     711
    700712        if (pVirtio->fGenUpdatePending || fDevSpecificFieldChanged)
    701713        {
    702             if (fDevSpecificFieldChanged)
    703                 Log2Func(("Dev specific config field changed since last read, gen++ = %d\n",
    704                      pVirtio->uConfigGeneration));
    705             else
    706                 Log2Func(("Config generation pending flag set, gen++ = %d\n",
    707                      pVirtio->uConfigGeneration));
    708714            ++pVirtio->uConfigGeneration;
     715            Log2Func(("Bumped cfg. generation to %d because %s %s\n",
     716                pVirtio->uConfigGeneration,
     717                fDevSpecificFieldChanged ? "<dev cfg changed> " : "",
     718                pVirtio->fGenUpdatePending ? "<update was pending>" : ""));
    709719            pVirtio->fGenUpdatePending = false;
    710720        }
     
    713723    if (fCommonCfg)
    714724    {
    715         uint32_t uCommonCfgDataOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg;
    716         virtioCommonCfgAccessed(pVirtio, 0 /* fWrite */, uCommonCfgDataOffset, cb, pv);
     725        uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg;
     726        virtioCommonCfgAccessed(pVirtio, 0 /* fWrite */, uOffset, cb, pv);
    717727    }
    718728    else
    719     if (fIsrCap)
     729    if (fIsr && cb == sizeof(uint8_t))
    720730    {
    721731        *(uint8_t *)pv = pVirtio->uISR;
    722         Log2Func(("Read 0x%02x from uISR (virtq interrupt: %d, dev config interrupt: %d)\n",
    723               pVirtio->uISR & 0xff,
    724               pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
     732        Log2Func(("Read and clear 0x%02x from uISR (interrupt type: virtq: %d, dev config: %d)\n",
     733              pVirtio->uISR, pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
    725734              !!(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG)));
    726735        pVirtio->uISR = 0; /** VirtIO specification requires reads of ISR to clear it */
     
    753762    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap,     fDevSpecific);
    754763    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysCommonCfg, pVirtio->pCommonCfgCap,  fCommonCfg);
    755     MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap,    pVirtio->pIsrCap,        fIsrCap);
    756     MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysNotifyCap, pVirtio->pNotifyCap,     fNotifyCap);
     764    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap,    pVirtio->pIsrCap,        fIsr);
     765    MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysNotifyCap, pVirtio->pNotifyCap,     fNotify);
    757766
    758767    if (fDevSpecific)
    759768    {
    760         uint32_t uDevSpecificDataOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap;
    761         rc = pVirtio->virtioCallbacks.pfnVirtioDevCapWrite(pDevIns, uDevSpecificDataOffset, pv, cb);
     769        uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap;
     770        /**
     771         * Pass this MMIO write access back to the client to handle
     772         */
     773        rc = pVirtio->virtioCallbacks.pfnVirtioDevCapWrite(pDevIns, uOffset, pv, cb);
    762774    }
    763775    else
    764776    if (fCommonCfg)
    765777    {
    766         uint32_t uCommonCfgDataOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg;
    767         virtioCommonCfgAccessed(pVirtio, 1 /* fWrite */, uCommonCfgDataOffset, cb, pv);
     778        uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg;
     779        virtioCommonCfgAccessed(pVirtio, 1 /* fWrite */, uOffset, cb, pv);
    768780    }
    769781    else
    770     if (fIsrCap)
     782    if (fIsr && cb == sizeof(uint8_t))
    771783    {
    772784        pVirtio->uISR = *(uint8_t *)pv;
    773         Log2Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg innterrupt: %d)\n",
     785        Log2Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg interrupt: %d)\n",
    774786              pVirtio->uISR & 0xff,
    775787              pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
     
    777789    }
    778790    else
    779     if (fNotifyCap && cb == 2)
     791    /** This *should* be guest driver dropping index of a new descriptor in avail ring */
     792    if (fNotify && cb == sizeof(uint16_t))
    780793    {
    781794        uint32_t uNotifyBaseOffset = GCPhysAddr - pVirtio->pGcPhysNotifyCap;
    782795        uint16_t qIdx = uNotifyBaseOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER;
    783         uint16_t uNotifiedIdx = *(uint16_t *)pv;
    784         vqDeviceNotified(pVirtio, qIdx, uNotifiedIdx);
     796        uint16_t uAvailDescIdx = *(uint16_t *)pv;
     797        virtioQueueNotified(pVirtio, qIdx, uAvailDescIdx);
    785798    }
    786799    else
     
    825838        pVirtio->pGcPhysNotifyCap  = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset;
    826839        pVirtio->pGcPhysIsrCap     = GCPhysAddress + pVirtio->pIsrCap->uOffset;
    827         if (pVirtio->pDevSpecificCap)
     840        if (pVirtio->pPrevDevSpecificCfg)
    828841            pVirtio->pGcPhysDeviceCap = GCPhysAddress + pVirtio->pDeviceCap->uOffset;
    829842    }
     
    948961 *
    949962 * @param   pDevIns                  Device instance data
     963 * @param   pClientContext           Opaque client context (such as state struct, ...)
    950964 * @param   pVirtio                  Device State
    951965 * @param   pPciParams               Values to populate industry standard PCI Configuration Space data structure
     
    960974 * @param   ssmLoadExecCallback      Client handler for SSM load exec
    961975 * @param   ssmLoadDoneCallback      Client handler for SSM load done
    962  * @param   cbDevSpecificCap         Size of virtio_pci_device_cap device-specific struct
     976 * @param   cbDevSpecificCfg         Size of virtio_pci_device_cap device-specific struct
     977 * @param   pDevSpecificCfg          Address of client's dev-specific configuration struct.
    963978 */
    964979int   virtioConstruct(PPDMDEVINS             pDevIns,
     980                      void                  *pClientContext,
    965981                      VIRTIOHANDLE          *phVirtio,
    966982                      PVIRTIOPCIPARAMS       pPciParams,
     
    975991                      PFNSSMDEVLOADEXEC      ssmLoadExecCallback,
    976992                      PFNSSMDEVLOADDONE      ssmLoadDoneCallback,
    977                       uint16_t               cbDevSpecificCap,
    978                       void                  *pDevSpecificCap)
     993                      uint16_t               cbDevSpecificCfg,
     994                      void                  *pDevSpecificCfg)
    979995{
    980996
    981997    int rc = VINF_SUCCESS;
    982998
    983     PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAlloc(sizeof(VIRTIOSTATE));
     999
     1000    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAllocZ(sizeof(VIRTIOSTATE));
    9841001    if (!pVirtio)
    9851002    {
     
    9871004        return VERR_NO_MEMORY;
    9881005    }
     1006
     1007    pVirtio->pClientContext = pClientContext;
    9891008
    9901009    /**
     
    10021021    pVirtio->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
    10031022    pVirtio->uDeviceStatus = 0;
    1004     pVirtio->cbDevSpecificCap = cbDevSpecificCap;
    1005     pVirtio->pDevSpecificCap  = pDevSpecificCap;
    1006 
    1007     pVirtio->pPrevDevSpecificCap = RTMemAlloc(cbDevSpecificCap);
    1008     if (!pVirtio->pPrevDevSpecificCap)
     1023    pVirtio->cbDevSpecificCfg = cbDevSpecificCfg;
     1024    pVirtio->pDevSpecificCfg  = pDevSpecificCfg;
     1025
     1026    pVirtio->pPrevDevSpecificCfg = RTMemAlloc(cbDevSpecificCfg);
     1027    if (!pVirtio->pPrevDevSpecificCfg)
    10091028    {
    10101029        RTMemFree(pVirtio);
     
    10131032    }
    10141033
    1015     memcpy(pVirtio->pPrevDevSpecificCap, pVirtio->pDevSpecificCap, cbDevSpecificCap);
     1034    memcpy(pVirtio->pPrevDevSpecificCfg, pVirtio->pDevSpecificCfg, cbDevSpecificCfg);
    10161035    pVirtio->virtioCallbacks.pfnVirtioDevCapRead    = devCapReadCallback;
    10171036    pVirtio->virtioCallbacks.pfnVirtioDevCapWrite   = devCapWriteCallback;
     
    11081127    pVirtio->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER;
    11091128
    1110     /** ISR capability (VirtIO 1.0 spec, section 4.1.4.5) */
     1129    /** ISR capability (VirtIO 1.0 spec, section 4.1.4.5)
     1130     *
     1131     * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram
     1132     * of spec shows it as a 32-bit field with upper bits 'reserved'
     1133     * Will take spec words very literally for now and check linux driver.
     1134     */
    11111135    pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
    11121136    pCfg->uCfgType = VIRTIO_PCI_CAP_ISR_CFG;
     
    11161140    pCfg->uBar     = VIRTIOSCSI_REGION_PCI_CAP;
    11171141    pCfg->uOffset  = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength;
    1118     pCfg->uLength  = sizeof(VIRTIO_PCI_ISR_CAP_T);
     1142    pCfg->uLength  = sizeof(uint8_t);
    11191143    cbRegion += pCfg->uLength;
    11201144    pVirtio->pIsrCap = pCfg;
     
    11241148     *  by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write
    11251149     *  values from any region. NOTE: The linux driver not only doesn't use this feature, and will not
    1126      *  even list it as present if uLength isn't non-zero and 4-byte-aligned as the linux driver is initializing */
     1150     *  even list it as present if uLength isn't non-zero and 4-byte-aligned as the linux driver is
     1151     *  initializing. */
    11271152
    11281153    pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
     
    11301155    pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
    11311156    pCfg->uCapLen  = sizeof(VIRTIO_PCI_CFG_CAP_T);
    1132     pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
     1157    pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCfg) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;
    11331158    pCfg->uBar     = 0;
    11341159    pCfg->uOffset  = 0;
     
    11371162    pVirtio->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg;
    11381163
    1139     if (pVirtio->pDevSpecificCap)
     1164    if (pVirtio->pDevSpecificCfg)
    11401165    {
    11411166        /** Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the
     
    11491174        pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
    11501175        pCfg->uOffset  = RT_ALIGN_32(pCfg->uOffset, 4);
    1151         pCfg->uLength  = cbDevSpecificCap;
     1176        pCfg->uLength  = cbDevSpecificCfg;
    11521177        cbRegion += pCfg->uLength;
    11531178        pVirtio->pDeviceCap = pCfg;
     
    11801205    if (RT_FAILURE(rc))
    11811206    {
    1182         RTMemFree(pVirtio->pPrevDevSpecificCap);
     1207        RTMemFree(pVirtio->pPrevDevSpecificCfg);
    11831208        RTMemFree(pVirtio);
    11841209        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    11941219#  ifdef DEBUG
    11951220
    1196         static void virtioDumpState(PVIRTIOSTATE pVirtio, const char *pcszCaller)
    1197         {
    1198             Log2Func(("(called from %s)\n"
    1199                       "  uDeviceFeatures          = 0x%08x\n"
    1200                       "  uDriverFeatures          = 0x%08x\n"
    1201                       "  uDeviceFeaturesSelect    = 0x%04x\n"
    1202                       "  uGuestFeaturesSelect     = 0x%04x\n"
    1203                       "  uDeviceStatus            = 0x%02x\n"
    1204                       "  uConfigGeneration        = 0x%02x\n"
    1205                       "  uQueueSelect             = 0x%04x\n"
    1206                       "  uNumQueues               = 0x%04x\n"
    1207                       "  uISR                     = 0x%02x\n"
    1208                       "  fGenUpdatePending        = 0x%02x\n"
    1209                       "  uPciCfgDataOff           = 0x%02x\n"
    1210                       "  pGcPhysPciCapBase        = %RGp\n"
    1211                       "  pGcPhysCommonCfg         = %RGp\n"
    1212                       "  pGcPhysNotifyCap         = %RGp\n"
    1213                       "  pGcPhysIsrCap            = %RGp\n"
    1214                       "  pGcPhysDeviceCap         = %RGp\n"
    1215                       "  pDevSpecificCap          = %p\n"
    1216                       "  cbDevSpecificCap         = 0x%04x\n"
    1217                       "  pfnVirtioStatusChanged   = %p\n"
    1218                       "  pfnVirtioQueueNotified   = %p\n"
    1219                       "  pfnVirtioDevCapRead      = %p\n"
    1220                       "  pfnVirtioDevCapWrite     = %p\n"
    1221                       "  pfnSSMDevLiveExec        = %p\n"
    1222                       "  pfnSSMDevSaveExec        = %p\n"
    1223                       "  pfnSSMDevLoadExec        = %p\n"
    1224                       "  pfnSSMDevLoadDone        = %p\n"
    1225                       "  pfnPciConfigReadOld      = %p\n"
    1226                       "  pfnPciConfigWriteOld     = %p\n",
    1227                             pcszCaller,
    1228                             pVirtio->uDeviceFeatures,
    1229                             pVirtio->uDriverFeatures,
    1230                             pVirtio->uDeviceFeaturesSelect,
    1231                             pVirtio->uDriverFeaturesSelect,
    1232                             pVirtio->uDeviceStatus,
    1233                             pVirtio->uConfigGeneration,
    1234                             pVirtio->uQueueSelect,
    1235                             pVirtio->uNumQueues,
    1236                             pVirtio->uISR,
    1237                             pVirtio->fGenUpdatePending,
    1238                             pVirtio->uPciCfgDataOff,
    1239                             pVirtio->pGcPhysPciCapBase,
    1240                             pVirtio->pGcPhysCommonCfg,
    1241                             pVirtio->pGcPhysNotifyCap,
    1242                             pVirtio->pGcPhysIsrCap,
    1243                             pVirtio->pGcPhysDeviceCap,
    1244                             pVirtio->pDevSpecificCap,
    1245                             pVirtio->cbDevSpecificCap,
    1246                             pVirtio->virtioCallbacks.pfnVirtioStatusChanged,
    1247                             pVirtio->virtioCallbacks.pfnVirtioQueueNotified,
    1248                             pVirtio->virtioCallbacks.pfnVirtioDevCapRead,
    1249                             pVirtio->virtioCallbacks.pfnVirtioDevCapWrite,
    1250                             pVirtio->virtioCallbacks.pfnSSMDevLiveExec,
    1251                             pVirtio->virtioCallbacks.pfnSSMDevSaveExec,
    1252                             pVirtio->virtioCallbacks.pfnSSMDevLoadExec,
    1253                             pVirtio->virtioCallbacks.pfnSSMDevLoadDone,
    1254                             pVirtio->pfnPciConfigReadOld,
    1255                             pVirtio->pfnPciConfigWriteOld
    1256             ));
    1257 
    1258             for (uint16_t i = 0; i < pVirtio->uNumQueues; i++)
    1259             {
    1260                 Log2Func(("%s queue:\n",
    1261                           "  virtqShadow[%u].uAvailIdx   = %u\n"
    1262                           "  virtqShadow[%u].uUsedIdx    = %u\n"
    1263                           "  uQueueSize[%u]              = %u\n"
    1264                           "  uQueueNotifyOff[%u]         = %04x\n"
    1265                           "  uQueueMsixVector[%u]        = %04x\n"
    1266                           "  uQueueEnable[%u]            = %04x\n"
    1267                           "  pGcPhysQueueDesc[%u]        = %RGp\n"
    1268                           "  pGcPhysQueueAvail[%u]       = %RGp\n"
    1269                           "  pGcPhysQueueUsed[%u]        = %RGp\n",
    1270                                 i, pVirtio->virtqShadow[i].pcszName,
    1271                                 i, pVirtio->virtqShadow[i].uAvailIdx,
    1272                                 i, pVirtio->virtqShadow[i].uUsedIdx,
    1273                                 i, pVirtio->uQueueSize[i],
    1274                                 i, pVirtio->uQueueNotifyOff[i],
    1275                                 i, pVirtio->uQueueMsixVector[i],
    1276                                 i, pVirtio->uQueueEnable[i],
    1277                                 i, pVirtio->pGcPhysQueueDesc[i],
    1278                                 i, pVirtio->pGcPhysQueueAvail[i],
    1279                                 i, pVirtio->pGcPhysQueueUsed[i]
    1280                 ));
    1281             }
    1282         }
     1221static void virtioDumpState(PVIRTIOSTATE pVirtio, const char *pcszCaller)
     1222{
     1223    Log2Func(("(called from %s)\n"
     1224              "  uDeviceFeatures          = 0x%08x\n  uDriverFeatures          = 0x%08x\n"
     1225              "  uDeviceFeaturesSelect    = 0x%04x\n  uGuestFeaturesSelect     = 0x%04x\n"
     1226              "  uDeviceStatus            = 0x%02x\n  uConfigGeneration        = 0x%02x\n"
     1227              "  uQueueSelect             = 0x%04x\n  uNumQueues               = 0x%04x\n"
     1228              "  uISR                     = 0x%02x\n  fGenUpdatePending        = 0x%02x\n"
     1229              "  uPciCfgDataOff           = 0x%02x\n  pGcPhysPciCapBase        = %RGp\n"
     1230              "  pGcPhysCommonCfg         = %RGp\n  pGcPhysNotifyCap         = %RGp\n"
     1231              "  pGcPhysIsrCap            = %RGp\n  pGcPhysDeviceCap         = %RGp\n"
     1232              "  pDevSpecificCap          = %p\n  cbDevSpecificCap         = 0x%04x\n"
     1233              "  pfnVirtioStatusChanged   = %p\n  pfnVirtioQueueNotified   = %p\n"
     1234              "  pfnVirtioDevCapRead      = %p\n  pfnVirtioDevCapWrite     = %p\n"
     1235              "  pfnSSMDevLiveExec        = %p\n  pfnSSMDevSaveExec        = %p\n"
     1236              "  pfnSSMDevLoadExec        = %p\n  pfnSSMDevLoadDone        = %p\n"
     1237              "  pfnPciConfigReadOld      = %p\n  pfnPciConfigWriteOld     = %p\n",
     1238                    pcszCaller ? pcszCaller : "<unspecified>",
     1239                    pVirtio->uDeviceFeatures, pVirtio->uDriverFeatures, pVirtio->uDeviceFeaturesSelect,
     1240                    pVirtio->uDriverFeaturesSelect, pVirtio->uDeviceStatus, pVirtio->uConfigGeneration,
     1241                    pVirtio->uQueueSelect, pVirtio->uNumQueues, pVirtio->uISR, pVirtio->fGenUpdatePending,
     1242                    pVirtio->uPciCfgDataOff, pVirtio->pGcPhysPciCapBase, pVirtio->pGcPhysCommonCfg,
     1243                    pVirtio->pGcPhysNotifyCap, pVirtio->pGcPhysIsrCap, pVirtio->pGcPhysDeviceCap,
     1244                    pVirtio->pDevSpecificCfg, pVirtio->cbDevSpecificCfg, pVirtio->virtioCallbacks.pfnVirtioStatusChanged,
     1245                    pVirtio->virtioCallbacks.pfnVirtioQueueNotified, pVirtio->virtioCallbacks.pfnVirtioDevCapRead,
     1246                    pVirtio->virtioCallbacks.pfnVirtioDevCapWrite, pVirtio->virtioCallbacks.pfnSSMDevLiveExec,
     1247                    pVirtio->virtioCallbacks.pfnSSMDevSaveExec, pVirtio->virtioCallbacks.pfnSSMDevLoadExec,
     1248                    pVirtio->virtioCallbacks.pfnSSMDevLoadDone, pVirtio->pfnPciConfigReadOld,
     1249                    pVirtio->pfnPciConfigWriteOld
     1250    ));
     1251
     1252    for (uint16_t i = 0; i < pVirtio->uNumQueues; i++)
     1253    {
     1254        Log2Func(("%s queue:\n",
     1255                  "  virtqProxy[%u].uAvailIdx   = %u\n  virtqProxy[%u].uUsedIdx    = %u\n"
     1256                  "  uQueueSize[%u]              = %u\n  uQueueNotifyOff[%u]         = %04x\n"
     1257                  "  uQueueMsixVector[%u]        = %04x\n  uQueueEnable[%u]            = %04x\n"
     1258                  "  pGcPhysQueueDesc[%u]        = %RGp\n  pGcPhysQueueAvail[%u]       = %RGp\n"
     1259                  "  pGcPhysQueueUsed[%u]        = %RGp\n",
     1260                        i, pVirtio->virtqProxy[i].szName, i, pVirtio->virtqProxy[i].uAvailIdx,
     1261                        i, pVirtio->virtqProxy[i].uUsedIdx, i, pVirtio->uQueueSize[i],
     1262                        i, pVirtio->uQueueNotifyOff[i],i, pVirtio->uQueueMsixVector[i],
     1263                        i, pVirtio->uQueueEnable[i], i, pVirtio->pGcPhysQueueDesc[i],
     1264                        i, pVirtio->pGcPhysQueueAvail[i], i, pVirtio->pGcPhysQueueUsed[i]
     1265        ));
     1266    }
     1267}
    12831268#  endif
    12841269#endif
     
    13031288    rc = SSMR3PutU32(pSSM,    pVirtio->uDriverFeaturesSelect);
    13041289    rc = SSMR3PutU32(pSSM,    pVirtio->uNumQueues);
    1305     rc = SSMR3PutU32(pSSM,    pVirtio->cbDevSpecificCap);
     1290    rc = SSMR3PutU32(pSSM,    pVirtio->cbDevSpecificCfg);
    13061291    rc = SSMR3PutU64(pSSM,    pVirtio->uDeviceFeatures);
    13071292    rc = SSMR3PutU64(pSSM,    pVirtio->uDriverFeatures);
    1308     rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->pDevSpecificCap);
     1293    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->pDevSpecificCfg);
    13091294    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->virtioCallbacks.pfnVirtioStatusChanged);
    13101295    rc = SSMR3PutU64(pSSM,    (uint64_t)pVirtio->virtioCallbacks.pfnVirtioQueueNotified);
     
    13321317        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueEnable[i]);
    13331318        rc = SSMR3PutU16(pSSM,      pVirtio->uQueueSize[i]);
    1334         rc = SSMR3PutU16(pSSM,      pVirtio->virtqShadow[i].uAvailIdx);
    1335         rc = SSMR3PutU16(pSSM,      pVirtio->virtqShadow[i].uUsedIdx);
    1336         rc = SSMR3PutMem(pSSM,      pVirtio->virtqShadow[i].pcszName, 32);
     1319        rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uAvailIdx);
     1320        rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uUsedIdx);
     1321        rc = SSMR3PutMem(pSSM,      pVirtio->virtqProxy[i].szName, 32);
    13371322    }
    13381323
     
    13621347        rc = SSMR3GetU32(pSSM,   &pVirtio->uDriverFeaturesSelect);
    13631348        rc = SSMR3GetU32(pSSM,   &pVirtio->uNumQueues);
    1364         rc = SSMR3GetU32(pSSM,   &pVirtio->cbDevSpecificCap);
     1349        rc = SSMR3GetU32(pSSM,   &pVirtio->cbDevSpecificCfg);
    13651350        rc = SSMR3GetU64(pSSM,   &pVirtio->uDeviceFeatures);
    13661351        rc = SSMR3GetU64(pSSM,   &pVirtio->uDriverFeatures);
    1367         rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->pDevSpecificCap);
     1352        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->pDevSpecificCfg);
    13681353        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioStatusChanged);
    13691354        rc = SSMR3GetU64(pSSM,   (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioQueueNotified);
     
    13911376            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueEnable[i]);
    13921377            rc = SSMR3GetU16(pSSM,      &pVirtio->uQueueSize[i]);
    1393             rc = SSMR3GetU16(pSSM,      &pVirtio->virtqShadow[i].uAvailIdx);
    1394             rc = SSMR3GetU16(pSSM,      &pVirtio->virtqShadow[i].uUsedIdx);
    1395             rc = SSMR3GetMem(pSSM,      pVirtio->virtqShadow[i].pcszName, 32);
     1378            rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uAvailIdx);
     1379            rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uUsedIdx);
     1380            rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqProxy[i].szName, 32);
    13961381        }
    13971382    }
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r80306 r80340  
    3434  * TEMPORARY NOTE: Some of these values are experimental during development and will likely change.
    3535  */
    36 #define VIRTQ_MAX_SIZE                      32768                /**< Max size (# desc elements) of a virtq    */
     36#define VIRTIO_MAX_QUEUE_NAME_SIZE          32                   /**< Maximum length of a queue name           */
     37#define VIRTQ_MAX_SIZE                      1024                 /**< Max size (# desc elements) of a virtq    */
    3738#define VIRTQ_MAX_CNT                       24                   /**< Max queues we allow guest to create      */
     39#define VIRTQ_DESC_MAX_SIZE                 (2 * 1024 * 1024)
    3840#define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
    39 #define VIRTQ_DESC_MAX_SIZE                 (2 * 1024 * 1024)
    4041#define VIRTIOSCSI_REGION_MEM_IO            0                    /**< BAR for MMIO (implementation specific)   */
    4142#define VIRTIOSCSI_REGION_PORT_IO           1                    /**< BAR for PORT I/O (impl specific)         */
    4243#define VIRTIOSCSI_REGION_PCI_CAP           2                    /**< BAR for VirtIO Cap. MMIO (impl specific) */
    43 
    4444typedef struct VIRTQ_SEG                                         /**< Describes one segment of a buffer vector */
    4545{
     
    4949} VIRTQ_SEG_T;
    5050
    51 typedef struct VIRTQ_BUF_VECTOR                                  /**< Scatter/gather buffer vector             */
     51    typedef struct VIRTQ_BUF_VECTOR                                  /**< Scatter/gather buffer vector             */
    5252{
    5353    uint32_t    uDescIdx;                                        /**< Desc at head of this vector list         */
     
    8181 * @param hVirtio       Handle to VirtIO framework
    8282 * @param fDriverOk     True if guest driver is okay (thus queues, etc... are valid)
    83  */
    84 typedef DECLCALLBACK(void)   FNVIRTIOSTATUSCHANGED(VIRTIOHANDLE hVirtio, bool fDriverOk);
     83 * @param pClient       Pointer to opaque client data (state)
     84 */
     85typedef DECLCALLBACK(void)   FNVIRTIOSTATUSCHANGED(VIRTIOHANDLE hVirtio, void *pClient, bool fDriverOk);
    8586typedef FNVIRTIOSTATUSCHANGED *PFNVIRTIOSTATUSCHANGED;
    8687
     
    9192 * @param   hVirtio     Handle to the VirtIO framework
    9293 * @param   qIdx        Index of the notified queue
    93  */
    94 typedef DECLCALLBACK(void)   FNVIRTIOQUEUENOTIFIED(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     94 * @param   pClient     Pointer to opaque client data (state)
     95 */
     96typedef DECLCALLBACK(void)   FNVIRTIOQUEUENOTIFIED(VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx);
    9597typedef FNVIRTIOQUEUENOTIFIED *PFNVIRTIOQUEUENOTIFIED;
    9698
     
    125127{
    126128     DECLCALLBACKMEMBER(void, pfnVirtioStatusChanged)
    127                                   (VIRTIOHANDLE hVirtio, bool fDriverOk);
     129                                  (VIRTIOHANDLE hVirtio, void *pClient, bool fDriverOk);
    128130     DECLCALLBACKMEMBER(void, pfnVirtioQueueNotified)
    129                                   (VIRTIOHANDLE hVirtio, uint16_t qIdx);
     131                                  (VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx);
    130132     DECLCALLBACKMEMBER(int,  pfnVirtioDevCapRead)
    131133                                  (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbRead);
     
    144146/** @} */
    145147
    146 /**
    147  * API to for VirtIO client below this point.
    148  */
    149 bool          virtioQueueAttach  (VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName);
    150 const char *  virtioQueueGetName (VIRTIOHANDLE hVirtio, uint16_t qIdx);
    151 bool          virtioQueuePeek    (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec);
    152 bool          virtioQueueGet     (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, bool fRemove);
    153 void          virtioQueuePut     (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, uint32_t cb);
    154 void          virtioQueueSync    (VIRTIOHANDLE hVirtio, uint16_t qIdx);
    155 bool          virtioQueueIsEmpty (VIRTIOHANDLE hVirtio, uint16_t qIdx);
    156 void          virtioResetAll     (VIRTIOHANDLE hVirtio);
     148/** API for VirtIO client */
     149
     150/**
     151 * Allocate client context for client to work with VirtIO-provided with queue
     152 * As a side effect creates a buffer vector a client can get a pointer to
     153 * with a call to virtioQueueBufVec()
     154 *
     155 * @param  hVirtio   - Handle to VirtIO framework
     156 * @param  qIdx      - Queue number
     157 * @param  pcszName  - Name to give queue
     158 *
     159 * @returns status     VINF_SUCCESS         - Success
     160 *                     VERR_INVALID_STATE   - VirtIO not in ready state
     161 *                     VERR_NO_MEMORY       - Out of memory
     162 *
     163 * @returns status. If false, the call failed and the client should call virtioResetAll()
     164 */
     165int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName);
     166/**
     167 * Detaches from queue and release resources
     168 *
     169 * @param hVirtio   - Handle for VirtIO framework
     170 * @param qIdx      - Queue number
     171 *
     172 */
     173int virtioQueueDetach(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     174
     175/**
     176 * Return pointer to buffer vector object associated with queue
     177 *
     178 * @param hVirtio   - Handle for VirtIO framework
     179 * @param qIdx      - Queue number
     180 *
     181 * @returns           Pointer pBufVec if success, else NULL
     182 */
     183PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     184
     185/**
     186 * Get name of queue, by qIdx, assigned at virtioQueueAttach()
     187 *
     188 * @param hVirtio   - Handle for VirtIO framework
     189 * @param qIdx      - Queue number
     190 *
     191 * @returns          Success: Returns pointer to queue name
     192 *                   Failure: Returns "<null>" (never returns NULL pointer).
     193 */
     194const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     195
     196/**
     197 * Removes descriptor [chain] from queue and converts it to scatter/gather data
     198 * in the vector whose pointer was returned from VirtioQueueAttach.
     199 *
     200 * @param hVirtio   - Handle for VirtIO framework
     201 * @param qIdx      - Queue number
     202 *
     203 * @returns status    VINF_SUCCESS         - Success
     204 *                    VERR_INVALID_STATE   - VirtIO not in ready state
     205 */
     206int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove);
     207
     208/**
     209 * Same as virtioQueueGet() but leaves the item on the avail ring of the queue.
     210 *
     211 * @param hVirtio   - Handle for VirtIO framework
     212 * @param qIdx      - Queue number
     213 *
     214 * @returns           VINF_SUCCESS         - Success
     215 *                    VERR_INVALID_STATE   - VirtIO not in ready state
     216 *                    VERR_NOT_AVAILABLE   - Queue is empty
     217 */
     218int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     219
     220/**
     221 * Writes scatter/gather segment contained in queue's bufVec.aSegsIn[] array to
     222 * physical memory assigned by the guest driver. The data won't be seen by the
     223 * driver until the next virtioQueueSync() call.
     224 *
     225 * @param hVirtio   - Handle for VirtIO framework
     226 * @param qIdx      - Queue number
     227 *
     228 * @returns           VINF_SUCCESS         - Success
     229 *                    VERR_INVALID_STATE   - VirtIO not in ready state
     230 *                    VERR_NOT_AVAILABLE   - Queue is empty
     231 */
     232int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, uint32_t cb);
     233
     234/**
     235 * Updates virtq's "used ring" descriptor index to match the current bufVec's
     236 * index, thus exposing the data added to the used ring by all virtioQueuePut()
     237 * calls since the last sync. This should be called after one or more virtQueuePut()
     238 * calls to inform the guest driver there is data in the queue. Explicit
     239 * notifications will be sent to the guest depending on VirtIO features negotiated
     240 * and conditions.
     241 *
     242 * @param hVirtio   - Handle for VirtIO framework
     243 * @param qIdx      - Queue number
     244 *
     245 * @returns           VINF_SUCCESS         - Success
     246 *                    VERR_INVALID_STATE   - VirtIO not in ready state
     247 */
     248int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx);
     249
     250/**
     251 * Check if the associated queue is empty
     252 *
     253 * @param hVirtio   - Handle for VirtIO framework
     254 * @param qIdx      - Queue number
     255 *
     256 * @returns           true     - Queue is empty or unavailable.
     257 *                    false    - Queue is available and has entries
     258 */
     259bool virtioQueueIsEmpty (VIRTIOHANDLE hVirtio, uint16_t qIdx);
     260
     261/**
     262 * Request orderly teardown of VirtIO on host and guest
     263 */
     264void virtioResetAll(VIRTIOHANDLE hVirtio);
    157265
    158266/** CLIENT MUST CALL ON RELOCATE CALLBACK! */
    159 void          virtioRelocate     (PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
     267void virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta);
    160268
    161269/**
     
    163271 *
    164272 * @param   pDevIns                  Device instance data
     273 * @param   pClientContext           Opaque client context (such as state struct)
    165274 * @param   pVirtio                  Device State
    166275 * @param   pPciParams               Values to populate industry standard PCI Configuration Space data structure
     
    175284 * @param   ssmLoadExecCallback      Client handler for SSM load exec
    176285 * @param   ssmLoadDoneCallback      Client handler for SSM load done
    177  * @param   cbDevSpecificCap         Size of virtio_pci_device_cap device-specific struct
     286 * @param   cbDevSpecificCfg         Size of virtio_pci_device_cap device-specific configuration struct
     287 * @param   pDevSpecificCfg          Address of client's VirtIO dev-specific configuration struct
    178288 */
    179289int  virtioConstruct(PPDMDEVINS             pDevIns,
     290                     void                  *pClientContext,
    180291                     VIRTIOHANDLE          *phVirtio,
    181292                     PVIRTIOPCIPARAMS       pPciParams,
     
    190301                     PFNSSMDEVLOADEXEC      ssmLoadExecCallback,
    191302                     PFNSSMDEVLOADDONE      ssmLoadDoneCallback,
    192                      uint16_t               cbDevSpecificCap,
    193                      void                  *pDevSpecificCap);
     303                     uint16_t               cbDevSpecificCfg,
     304                     void                  *pDevSpecificCfg);
    194305
    195306/**
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r80308 r80340  
    8787 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification)
    8888 */
    89 typedef struct VIRTQ_SHADOW
    90 {
    91     const char *pcszName[32];                                   /**< Dev-specific name of queue                */
    92     uint16_t    uAvailIdx;                                      /**< Consumer's position in avail ring         */
    93     uint16_t    uUsedIdx;                                       /**< Consumer's position in used ring          */
    94     bool        fEventThresholdReached;                         /**< Don't lose track while queueing ahead     */
    95 } VIRTQ_SHADOW_T, *PVIRTQ_SHADOW_T;
     89typedef struct VIRTQ_PROXY
     90{
     91    const char          szName[32];                              /**< Dev-specific name of queue                */
     92    PVIRTQ_BUF_VECTOR_T pBufVec;                                 /**< Per-queue s/g data. Serialize access!     */
     93    uint16_t            uAvailIdx;                               /**< Consumer's position in avail ring         */
     94    uint16_t            uUsedIdx;                                /**< Consumer's position in used ring          */
     95    bool                fEventThresholdReached;                  /**< Don't lose track while queueing ahead     */
     96} VIRTQ_PROXY_T, *PVIRTQ_PROXY_T;
    9697
    9798/**
     
    135136} VIRTIO_PCI_CFG_CAP_T,   *PVIRTIO_PCI_CFG_CAP_T;
    136137
    137 /** For ISR, spec says min. 1 byte. Diagram shows 32-bits, mostly reserved */
    138 typedef uint32_t VIRTIO_PCI_ISR_CAP_T, *PVIRTIO_PCI_ISR_CAP_T;
    139138
    140139/**
     
    147146    PDMPCIDEV                 dev;                               /**< PCI device                                */
    148147    char                      szInstance[16];                    /**< Instance name, e.g. "VIRTIOSCSI0"         */
     148    void *                    pClientContext;                     /**< Client callback returned on callbacks     */
    149149
    150150    PPDMDEVINSR3              pDevInsR3;                         /**< Device instance - R3                      */
     
    177177    uint8_t                   uConfigGeneration;                 /**< (MMIO) Device config sequencer       HOST */
    178178
    179     VIRTQ_SHADOW_T            virtqShadow[VIRTQ_MAX_CNT];        /**< Local impl-specific queue context         */
     179    VIRTQ_PROXY_T             virtqProxy[VIRTQ_MAX_CNT];        /**< Local impl-specific queue context         */
    180180    VIRTIOCALLBACKS           virtioCallbacks;                   /**< Callback vectors to client                */
    181181
     
    189189    PVIRTIO_PCI_CAP_T         pDeviceCap;                        /**< Pointer to struct in configuration area   */
    190190
    191     uint32_t                  cbDevSpecificCap;                  /**< Size of client's dev-specific config data */
    192     void                     *pDevSpecificCap;                   /**< Pointer to client's struct                */
    193     void                     *pPrevDevSpecificCap;               /**< Previous read dev-specific cfg of client  */
     191    uint32_t                  cbDevSpecificCfg;                  /**< Size of client's dev-specific config data */
     192    void                     *pDevSpecificCfg;                   /**< Pointer to client's struct                */
     193    void                     *pPrevDevSpecificCfg;               /**< Previous read dev-specific cfg of client  */
    194194    bool                      fGenUpdatePending;                 /**< If set, update cfg gen after driver reads */
    195195    uint8_t                   uPciCfgDataOff;
     
    329329    }
    330330
     331#define DRIVER_OK(pVirtio) (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
     332
    331333/**
    332334 * Internal queue operations
     
    335337static int         vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
    336338static bool        vqIsEmpty              (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    337 static void        vqReset                (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    338339static void        vqReadDesc             (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc);
    339340static uint16_t    vqReadAvailRingDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx);
     
    356357DECLINLINE(bool) vqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx)
    357358{
    358     return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->virtqShadow->uAvailIdx;
     359    return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->virtqProxy->uAvailIdx;
    359360}
    360361
     
    511512}
    512513
    513 static void vqReset                 (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    514 static void vqDeviceNotified        (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx);
     514static void virtioResetQueue        (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    515515static void vqNotifyDriver          (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    516516static int  virtioRaiseInterrupt    (PVIRTIOSTATE pVirtio, uint8_t uCause);
    517517static void virtioLowerInterrupt    (PVIRTIOSTATE pVirtio);
     518static void virtioQueueNotified     (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx);
    518519static int  virtioCommonCfgAccessed (PVIRTIOSTATE pVirtio, int fWrite, off_t uOffset, unsigned cb, void const *pv);
    519520static void virtioGuestResetted     (PVIRTIOSTATE pVirtio);
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