void vqueuePut(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen, uint32_t uReserved) { unsigned int i, uOffset, cbReserved = uReserved; Log2(("%s vqueuePut: %s desc_idx=%u acb=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pElem->uIndex, uLen)); for (i = uOffset = 0; i < pElem->nIn && uOffset < uLen - uReserved; i++) { uint32_t cbSegLen = RT_MIN(uLen - cbReserved - uOffset, pElem->aSegsIn[i].cb - cbReserved); if (pElem->aSegsIn[i].pv) { Log2(("%s vqueuePut: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pQueue->uNextUsedIndex, i, pElem->aSegsIn[i].addr, pElem->aSegsIn[i].pv, pElem->aSegsIn[i].cb, cbSegLen)); PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns), pElem->aSegsIn[i].addr + cbReserved, pElem->aSegsIn[i].pv, cbSegLen); cbReserved = 0; } uOffset += cbSegLen; } Assert((uReserved + uOffset) == uLen || pElem->nIn == 0); Log2(("%s vqueuePut: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pQueue->uNextUsedIndex, vringReadUsedIndex(pState, &pQueue->VRing), pElem->uIndex, uLen)); vringWriteUsedElem(pState, &pQueue->VRing, pQueue->uNextUsedIndex++, pElem->uIndex, uLen); }
void vqueueSync(PVPCISTATE pState, PVQUEUE pQueue) { Log2(("%s vqueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), vringReadUsedIndex(pState, &pQueue->VRing), pQueue->uNextUsedIndex)); vringWriteUsedIndex(pState, &pQueue->VRing, pQueue->uNextUsedIndex); vqueueNotify(pState, pQueue); }
bool vqueueGet(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove) { if (vqueueIsEmpty(pState, pQueue)) return false; pElem->nIn = pElem->nOut = 0; Log2(("%s vqueueGet: %s avail_idx=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex)); VRINGDESC desc; uint16_t idx = vringReadAvail(pState, &pQueue->VRing, pQueue->uNextAvailIndex); if (fRemove) pQueue->uNextAvailIndex++; pElem->uIndex = idx; do { VQUEUESEG *pSeg; vringReadDesc(pState, &pQueue->VRing, idx, &desc); if (desc.u16Flags & VRINGDESC_F_WRITE) { Log2(("%s vqueueGet: %s IN seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pElem->nIn, idx, desc.u64Addr, desc.uLen)); pSeg = &pElem->aSegsIn[pElem->nIn++]; } else { Log2(("%s vqueueGet: %s OUT seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pElem->nOut, idx, desc.u64Addr, desc.uLen)); pSeg = &pElem->aSegsOut[pElem->nOut++]; } pSeg->addr = desc.u64Addr; pSeg->cb = desc.uLen; pSeg->pv = NULL; idx = desc.u16Next; } while (desc.u16Flags & VRINGDESC_F_NEXT); Log2(("%s vqueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pElem->uIndex, pElem->nIn, pElem->nOut)); return true; }
bool vqueueSkip(PVPCISTATE pState, PVQUEUE pQueue) { if (vqueueIsEmpty(pState, pQueue)) return false; Log2(("%s vqueueSkip: %s avail_idx=%u\n", INSTANCE(pState), QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex)); pQueue->uNextAvailIndex++; return true; }
void vqueueNotify(PVPCISTATE pState, PVQUEUE pQueue) { LogFlow(("%s vqueueNotify: %s availFlags=%x guestFeatures=%x vqueue is %sempty\n", INSTANCE(pState), QUEUENAME(pState, pQueue), vringReadAvailFlags(pState, &pQueue->VRing), pState->uGuestFeatures, vqueueIsEmpty(pState, pQueue)?"":"not ")); if (!(vringReadAvailFlags(pState, &pQueue->VRing) & VRINGAVAIL_F_NO_INTERRUPT) || ((pState->uGuestFeatures & VPCI_F_NOTIFY_ON_EMPTY) && vqueueIsEmpty(pState, pQueue))) { int rc = vpciRaiseInterrupt(pState, VERR_INTERNAL_ERROR, VPCI_ISR_QUEUE); if (RT_FAILURE(rc)) Log(("%s vqueueNotify: Failed to raise an interrupt (%Rrc).\n", INSTANCE(pState), rc)); } else { STAM_COUNTER_INC(&pState->StatIntsSkipped); } }