Changeset 80762 in vbox for trunk/src/VBox/Devices/VirtIO
- Timestamp:
- Sep 13, 2019 2:33:47 AM (5 years ago)
- Location:
- trunk/src/VBox/Devices/VirtIO
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r80718 r80762 34 34 35 35 #define INSTANCE(pVirtio) pVirtio->szInstance 36 #define QUEUENAME(qIdx) (pVirtio->virtqProxy[qIdx].szVirtqName) 37 36 #define QUEUENAME(qIdx) (pVirtio->virtqState[qIdx].szVirtqName) 37 38 /** 39 * See API comments in header file for description 40 */ 41 void virtioVirtToSgPhys(VIRTIOHANDLE hVirtio, PRTSGBUF pSgDst, void *pvSrc, size_t cb) 42 { 43 while (cb) 44 { 45 size_t cbSeg = cb; 46 RTGCPHYS GCPhys = (RTGCPHYS)RTSgBufGetNextSegment(pSgDst, &cbSeg); 47 PDMDevHlpPhysWrite(((PVIRTIOSTATE)hVirtio)->CTX_SUFF(pDevIns), GCPhys, pvSrc, cbSeg); 48 pvSrc = ((uint8_t *)pvSrc) + cbSeg; 49 cb -= cbSeg; 50 } 51 } 52 53 /** 54 * See API comments in header file for description 55 */ 56 void virtioSgPhysToVirt(VIRTIOHANDLE hVirtio, PRTSGBUF pSgSrc, void *pvDst, size_t cb) 57 { 58 while (cb) 59 { 60 size_t cbSeg = cb; 61 RTGCPHYS GCPhys = (RTGCPHYS)RTSgBufGetNextSegment(pSgSrc, &cbSeg); 62 PDMDevHlpPhysRead(((PVIRTIOSTATE)hVirtio)->CTX_SUFF(pDevIns), GCPhys, pvDst, cbSeg); 63 pvDst = ((uint8_t *)pvDst) + cbSeg; 64 cb -= cbSeg; 65 } 66 } 38 67 39 68 /** … … 44 73 LogFunc(("%s\n", pcszName)); 45 74 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 46 PVIRTQ_PROXY_T pVirtqProxy = &(pVirtio->virtqProxy[qIdx]); 47 pVirtqProxy->pDescChain = (PVIRTQ_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTQ_DESC_CHAIN_T)); 48 if (!pVirtqProxy->pDescChain) 49 { 50 Log(("Out of memory!")); 51 return VERR_NO_MEMORY; 52 } 53 pVirtqProxy->uAvailIdx = 0; 54 pVirtqProxy->uUsedIdx = 0; 55 pVirtqProxy->fEventThresholdReached = false; 56 RTStrCopy((char *)pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName), pcszName); 75 PVIRTQSTATE pVirtq = &(pVirtio->virtqState[qIdx]); 76 pVirtq->uAvailIdx = 0; 77 pVirtq->uUsedIdx = 0; 78 pVirtq->fEventThresholdReached = false; 79 RTStrCopy((char *)pVirtq->szVirtqName, sizeof(pVirtq->szVirtqName), pcszName); 57 80 return VINF_SUCCESS; 58 81 … … 64 87 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx) 65 88 { 66 return (const char *)((PVIRTIOSTATE)hVirtio)->virtq Proxy[qIdx].szVirtqName;89 return (const char *)((PVIRTIOSTATE)hVirtio)->virtqState[qIdx].szVirtqName; 67 90 } 68 91 … … 72 95 int virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx) 73 96 { 74 Assert(qIdx < sizeof(VIRTQ _PROXY_T));97 Assert(qIdx < sizeof(VIRTQSTATE)); 75 98 76 99 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 77 PVIRTQ _PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];100 PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx]; 78 101 79 102 AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx], … … 83 106 return VERR_NOT_AVAILABLE; 84 107 85 Log2Func(("%s avail_idx=%u\n", pVirtq Proxy->szVirtqName, pVirtqProxy->uAvailIdx));86 pVirtq Proxy->uAvailIdx++;108 Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx)); 109 pVirtq->uAvailIdx++; 87 110 88 111 return VINF_SUCCESS; … … 112 135 * See API comments in header file for description 113 136 */ 114 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs) 115 { 116 return virtioQueueGet(hVirtio, qIdx, false /* fRemove */, ppInSegs, ppOutSegs); 117 } 118 119 /*/** 120 * See API comments in header file for description 121 */ 122 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, 123 PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs) 124 { 137 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove) 138 { 139 Assert(ppDescChain); 140 125 141 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 126 PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx]; 127 PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain; 142 PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx]; 143 144 PRTSGSEG paSegsIn = (PRTSGSEG)RTMemAlloc(VIRTQ_MAX_SIZE * sizeof(RTSGSEG)); 145 AssertReturn(paSegsIn, VERR_NO_MEMORY); 146 147 PRTSGSEG paSegsOut = (PRTSGSEG)RTMemAlloc(VIRTQ_MAX_SIZE * sizeof(RTSGSEG)); 148 AssertReturn(paSegsOut, VERR_NO_MEMORY); 128 149 129 150 AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx], … … 133 154 return VERR_NOT_AVAILABLE; 134 155 135 pDescChain->cSegsIn = pDescChain->cSegsOut = 0; 136 137 pDescChain->uHeadIdx = virtioReadAvailDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx); 138 uint16_t uDescIdx = pDescChain->uHeadIdx; 156 uint16_t uHeadIdx = virtioReadAvailDescIdx(pVirtio, qIdx, pVirtq->uAvailIdx); 157 uint16_t uDescIdx = uHeadIdx; 139 158 140 159 Log6Func(("%s DESC CHAIN: (head) desc_idx=%u [avail_idx=%u]\n", 141 pVirtq Proxy->szVirtqName, pDescChain->uHeadIdx, pVirtqProxy->uAvailIdx));160 pVirtq->szVirtqName, uHeadIdx, pVirtq->uAvailIdx)); 142 161 143 162 if (fRemove) 144 pVirtqProxy->uAvailIdx++; 145 146 uint32_t cbIn = 0, cbOut = 0; 163 pVirtq->uAvailIdx++; 164 147 165 VIRTQ_DESC_T desc; 166 167 uint32_t cbIn = 0, cbOut = 0, cSegsIn = 0, cSegsOut = 0; 168 148 169 do 149 170 { … … 151 172 152 173 /** 153 * Malicious guests may go beyond aSegsIn oraSegsOut boundaries by linking174 * Malicious guests may go beyond paSegsIn or paSegsOut boundaries by linking 154 175 * several descriptors into a loop. Since there is no legitimate way to get a sequences of 155 176 * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}), 156 177 * the following aborts I/O if breach and employs a simple log throttling algorithm to notify. 157 178 */ 158 if ( pDescChain->cSegsIn + pDescChain->cSegsOut >= VIRTQ_MAX_SIZE)179 if (cSegsIn + cSegsOut >= VIRTQ_MAX_SIZE) 159 180 { 160 181 static volatile uint32_t s_cMessages = 0; … … 178 199 { 179 200 Log6Func(("%s IN desc_idx=%u seg=%u addr=%RGp cb=%u\n", 180 QUEUENAME(qIdx), uDescIdx, pDescChain->cSegsIn, desc.pGcPhysBuf, desc.cb));201 QUEUENAME(qIdx), uDescIdx, cSegsIn, desc.pGcPhysBuf, desc.cb)); 181 202 cbIn += desc.cb; 182 pSeg = &(p DescChain->aSegsIn[pDescChain->cSegsIn++]);203 pSeg = &(paSegsIn[cSegsIn++]); 183 204 } 184 205 else 185 206 { 186 207 Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", 187 QUEUENAME(qIdx), uDescIdx, pDescChain->cSegsOut, desc.pGcPhysBuf, desc.cb));208 QUEUENAME(qIdx), uDescIdx, cSegsOut, desc.pGcPhysBuf, desc.cb)); 188 209 cbOut += desc.cb; 189 pSeg = &(p DescChain->aSegsOut[pDescChain->cSegsOut++]);210 pSeg = &(paSegsOut[cSegsOut++]); 190 211 } 191 212 … … 196 217 } while (desc.fFlags & VIRTQ_DESC_F_NEXT); 197 218 198 RTSgBufInit(&pVirtqProxy->inSgBuf, (PCRTSGSEG)&pDescChain->aSegsIn, pDescChain->cSegsIn); 199 RTSgBufInit(&pVirtqProxy->outSgBuf, (PCRTSGSEG)&pDescChain->aSegsOut, pDescChain->cSegsOut); 200 201 if (ppInSegs) 202 *ppInSegs = &pVirtqProxy->inSgBuf; 203 204 if (ppOutSegs) 205 *ppOutSegs = &pVirtqProxy->outSgBuf; 219 220 PRTSGBUF pSgPhysIn = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF)); 221 AssertReturn(pSgPhysIn, VERR_NO_MEMORY); 222 223 RTSgBufInit(pSgPhysIn, (PCRTSGSEG)paSegsIn, cSegsIn); 224 225 void *pSgVirtOut = RTMemAlloc(cbOut); 226 AssertReturn(pSgVirtOut, VERR_NO_MEMORY); 227 228 if (cSegsOut) 229 { 230 RTSGBUF outSgPhys; 231 RTSgBufInit(&outSgPhys, (PCRTSGSEG)paSegsOut, cSegsOut); 232 virtioSgPhysToVirt((PVIRTIOSTATE)hVirtio, &outSgPhys, pSgVirtOut, cbOut); 233 RTMemFree(paSegsOut); 234 } 235 236 PVIRTIO_DESC_CHAIN_T pDescChain = (PVIRTIO_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTIO_DESC_CHAIN_T)); 237 AssertReturn(pDescChain, VERR_NO_MEMORY); 238 239 pDescChain->uHeadIdx = uHeadIdx; 240 pDescChain->cbVirtSrc = cbOut; 241 pDescChain->pVirtSrc = pSgVirtOut; 242 pDescChain->cbPhysDst = cbIn; 243 pDescChain->pSgPhysDst = pSgPhysIn; 244 *ppDescChain = pDescChain; 206 245 207 246 Log6Func(("%s -- segs OUT: %u (%u bytes) IN: %u (%u bytes) --\n", 208 pVirtq Proxy->szVirtqName, pDescChain->cSegsOut, cbOut, pDescChain->cSegsIn, cbIn));247 pVirtq->szVirtqName, cSegsOut, cbOut, cSegsIn, cbIn)); 209 248 210 249 return VINF_SUCCESS; … … 212 251 213 252 /** See API comments in header file prototype for description */ 214 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSg Buf, bool fFence)215 { 216 217 Assert(qIdx < sizeof(VIRTQ_PROXY_T));253 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgVirtReturn, 254 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence) 255 { 256 Assert(qIdx < VIRTQ_MAX_CNT); 218 257 219 258 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 220 PVIRTQ _PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];221 P VIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;259 PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx]; 260 PRTSGBUF pSgPhysReturn = pDescChain->pSgPhysDst; 222 261 223 262 AssertMsgReturn(DRIVER_OK(pVirtio) /*&& pVirtio->uQueueEnable[qIdx]*/, 224 263 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 225 /** 226 * Copy caller's virtual memory sg buffer to physical memory 227 */ 228 PRTSGBUF pBufSrc = pSgBuf; 229 PRTSGBUF pBufDst = &pVirtqProxy->inSgBuf; 230 231 size_t cbRemain = RTSgBufCalcTotalLength(pBufSrc); 264 232 265 uint16_t uUsedIdx = virtioReadUsedRingIdx(pVirtio, qIdx); 233 266 Log6Func(("Copying client data to %s, desc chain (head desc_idx %d)\n", 234 267 QUEUENAME(qIdx), uUsedIdx)); 235 268 269 /* 270 * Copy virtual memory s/g buffer containing data to return to the guest 271 * to phys. memory described by (IN direction ) s/g buffer of the descriptor chain 272 * original pulled from the queue, to 'send back' to the guest driver. 273 */ 274 size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn); 275 size_t cbCopy = 0; 236 276 while (cbRemain) 237 277 { 238 uint64_t dstSgStart = (uint64_t)pBufDst->paSegs[pBufDst->idxSeg].pvSeg; 239 uint64_t dstSgLen = (uint64_t)pBufDst->paSegs[pBufDst->idxSeg].cbSeg; 240 uint64_t dstSgCur = (uint64_t)pBufDst->pvSegCur; 241 size_t cbCopy = RT_MIN(pBufSrc->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart)); 278 PCRTSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg]; 279 uint64_t dstSgStart = (uint64_t)paSeg->pvSeg; 280 uint64_t dstSgLen = (uint64_t)paSeg->cbSeg; 281 uint64_t dstSgCur = (uint64_t)pSgPhysReturn->pvSegCur; 282 cbCopy = RT_MIN(pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart)); 242 283 PDMDevHlpPhysWrite(pVirtio->CTX_SUFF(pDevIns), 243 (RTGCPHYS)p BufDst->pvSegCur, pBufSrc->pvSegCur, cbCopy);244 RTSgBufAdvance(p BufSrc, cbCopy);245 RTSgBufAdvance(p BufDst, cbCopy);284 (RTGCPHYS)pSgPhysReturn->pvSegCur, pSgVirtReturn->pvSegCur, cbCopy); 285 RTSgBufAdvance(pSgVirtReturn, cbCopy); 286 RTSgBufAdvance(pSgPhysReturn, cbCopy); 246 287 cbRemain -= cbCopy; 247 288 } 289 248 290 249 291 if (fFence) … … 252 294 /** If this write-ahead crosses threshold where the driver wants to get an event flag it */ 253 295 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 254 if (pVirtq Proxy->uUsedIdx == virtioReadAvailUsedEvent(pVirtio, qIdx))255 pVirtq Proxy->fEventThresholdReached = true;296 if (pVirtq->uUsedIdx == virtioReadAvailUsedEvent(pVirtio, qIdx)) 297 pVirtq->fEventThresholdReached = true; 256 298 257 299 /** 258 300 * Place used buffer's descriptor in used ring but don't update used ring's slot index. 259 301 * That will be done with a subsequent client call to virtioQueueSync() */ 260 virtioWriteUsedElem(pVirtio, qIdx, 261 pVirtqProxy->uUsedIdx++, 262 pDescChain->uHeadIdx, 263 pDescChain->cSegsIn); 302 virtioWriteUsedElem(pVirtio, qIdx, pVirtq->uUsedIdx++, pDescChain->uHeadIdx, cbCopy); 303 264 304 265 305 if (LogIs2Enabled()) 266 306 { 267 size_t cbInSgBuf = RTSgBufCalcTotalLength(pBufDst);268 size_t cbWritten = cbInSgBuf - RTSgBufCalcLengthLeft(pBufDst);269 307 Log2Func((".... Copied %u bytes to %u byte buffer, residual=%d\n", 270 cb Written, cbInSgBuf, cbInSgBuf - cbWritten));308 cbCopy, pDescChain->cbPhysDst, pDescChain->cbPhysDst - cbCopy)); 271 309 } 272 310 Log6Func(("Write ahead used_idx=%d, %s used_idx=%d\n", 273 pVirtqProxy->uUsedIdx, QUEUENAME(qIdx), uUsedIdx)); 311 pVirtq->uUsedIdx, QUEUENAME(qIdx), uUsedIdx)); 312 313 RTMemFree((void *)pSgPhysReturn->paSegs); 314 RTMemFree(pSgPhysReturn); 315 RTMemFree(pDescChain); 274 316 275 317 return VINF_SUCCESS; … … 281 323 int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx) 282 324 { 283 Assert(qIdx < sizeof(VIRTQ _PROXY_T));325 Assert(qIdx < sizeof(VIRTQSTATE)); 284 326 285 327 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 286 PVIRTQ _PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];328 PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx]; 287 329 288 330 AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx], … … 291 333 uint16_t uIdx = virtioReadUsedRingIdx(pVirtio, qIdx); 292 334 Log6Func(("Updating %s used_idx from %u to %u\n", 293 QUEUENAME(qIdx), uIdx, pVirtq Proxy->uUsedIdx));294 295 virtioWriteUsedRingIdx(pVirtio, qIdx, pVirtq Proxy->uUsedIdx);335 QUEUENAME(qIdx), uIdx, pVirtq->uUsedIdx)); 336 337 virtioWriteUsedRingIdx(pVirtio, qIdx, pVirtq->uUsedIdx); 296 338 virtioNotifyGuestDriver(pVirtio, qIdx, false); 297 339 … … 306 348 Assert(uNotifyIdx == qIdx); 307 349 308 PVIRTQ _PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];309 Log6Func(("%s\n", pVirtq Proxy->szVirtqName));350 PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx]; 351 Log6Func(("%s\n", pVirtq->szVirtqName)); 310 352 311 353 /** Inform client */ … … 337 379 static void virtioNotifyGuestDriver(PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce) 338 380 { 339 PVIRTQ _PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];381 PVIRTQSTATE pVirtq = &pVirtio->virtqState[qIdx]; 340 382 341 383 AssertMsgReturnVoid(DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n")); … … 345 387 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 346 388 { 347 if (pVirtq Proxy->fEventThresholdReached)389 if (pVirtq->fEventThresholdReached) 348 390 { 349 391 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, fForce); 350 pVirtq Proxy->fEventThresholdReached = false;392 pVirtq->fEventThresholdReached = false; 351 393 return; 352 394 } … … 434 476 static void virtioResetQueue(PVIRTIOSTATE pVirtio, uint16_t qIdx) 435 477 { 436 PVIRTQ _PROXY_T pVirtQ = &pVirtio->virtqProxy[qIdx];478 PVIRTQSTATE pVirtQ = &pVirtio->virtqState[qIdx]; 437 479 pVirtQ->uAvailIdx = 0; 438 480 pVirtQ->uUsedIdx = 0; … … 832 874 Assert(cb >= 32); 833 875 834 if (iRegion == VIRTIO SCSI_REGION_PCI_CAP)876 if (iRegion == VIRTIO_REGION_PCI_CAP) 835 877 { 836 878 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */ … … 885 927 uint8_t uBar = pVirtio->pPciCfgCap->pciCap.uBar; 886 928 uint32_t pv = 0; 887 if (uBar == VIRTIO SCSI_REGION_PCI_CAP)929 if (uBar == VIRTIO_REGION_PCI_CAP) 888 930 (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset), 889 931 &pv, uLength); … … 929 971 uint32_t uOffset = pVirtio->pPciCfgCap->pciCap.uOffset; 930 972 uint8_t uBar = pVirtio->pPciCfgCap->pciCap.uBar; 931 if (uBar == VIRTIO SCSI_REGION_PCI_CAP)973 if (uBar == VIRTIO_REGION_PCI_CAP) 932 974 (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset), 933 975 (void *)&u32Value, uLength); … … 1117 1159 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1118 1160 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1119 pCfg->uBar = VIRTIO SCSI_REGION_PCI_CAP;1161 pCfg->uBar = VIRTIO_REGION_PCI_CAP; 1120 1162 pCfg->uOffset = RT_ALIGN_32(0, 4); /* reminder, in case someone changes offset */ 1121 1163 pCfg->uLength = sizeof(VIRTIO_PCI_COMMON_CFG_T); … … 1132 1174 pCfg->uCapLen = sizeof(VIRTIO_PCI_NOTIFY_CAP_T); 1133 1175 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1134 pCfg->uBar = VIRTIO SCSI_REGION_PCI_CAP;1176 pCfg->uBar = VIRTIO_REGION_PCI_CAP; 1135 1177 pCfg->uOffset = pVirtio->pCommonCfgCap->uOffset + pVirtio->pCommonCfgCap->uLength; 1136 1178 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 2); … … 1151 1193 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1152 1194 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1153 pCfg->uBar = VIRTIO SCSI_REGION_PCI_CAP;1195 pCfg->uBar = VIRTIO_REGION_PCI_CAP; 1154 1196 pCfg->uOffset = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength; 1155 1197 pCfg->uLength = sizeof(uint8_t); … … 1184 1226 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1185 1227 pCfg->uCapNext = fMsiSupport ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1186 pCfg->uBar = VIRTIO SCSI_REGION_PCI_CAP;1228 pCfg->uBar = VIRTIO_REGION_PCI_CAP; 1187 1229 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength; 1188 1230 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 4); … … 1214 1256 * out size, so pad with an extra page */ 1215 1257 1216 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIO SCSI_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + 0x1000, 0x1000),1258 rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + 0x1000, 0x1000), 1217 1259 PCI_ADDRESS_SPACE_MEM, virtioR3Map); 1218 1260 if (RT_FAILURE(rc)) … … 1266 1308 { 1267 1309 Log2Func(("%s queue:\n", 1268 " virtq Proxy[%u].uAvailIdx = %u\n virtqProxy[%u].uUsedIdx = %u\n"1310 " virtqState[%u].uAvailIdx = %u\n virtqState[%u].uUsedIdx = %u\n" 1269 1311 " uQueueSize[%u] = %u\n uQueueNotifyOff[%u] = %04x\n" 1270 1312 " uQueueMsixVector[%u] = %04x\n uQueueEnable[%u] = %04x\n" 1271 1313 " pGcPhysQueueDesc[%u] = %RGp\n pGcPhysQueueAvail[%u] = %RGp\n" 1272 1314 " pGcPhysQueueUsed[%u] = %RGp\n", 1273 i, pVirtio->virtq Proxy[i].szVirtqName, i, pVirtio->virtqProxy[i].uAvailIdx,1274 i, pVirtio->virtq Proxy[i].uUsedIdx, i, pVirtio->uQueueSize[i],1315 i, pVirtio->virtqState[i].szVirtqName, i, pVirtio->virtqState[i].uAvailIdx, 1316 i, pVirtio->virtqState[i].uUsedIdx, i, pVirtio->uQueueSize[i], 1275 1317 i, pVirtio->uQueueNotifyOff[i],i, pVirtio->uQueueMsixVector[i], 1276 1318 i, pVirtio->uQueueEnable[i], i, pVirtio->pGcPhysQueueDesc[i], … … 1330 1372 rc = SSMR3PutU16(pSSM, pVirtio->uQueueEnable[i]); 1331 1373 rc = SSMR3PutU16(pSSM, pVirtio->uQueueSize[i]); 1332 rc = SSMR3PutU16(pSSM, pVirtio->virtq Proxy[i].uAvailIdx);1333 rc = SSMR3PutU16(pSSM, pVirtio->virtq Proxy[i].uUsedIdx);1334 rc = SSMR3PutMem(pSSM, pVirtio->virtq Proxy[i].szVirtqName, 32);1374 rc = SSMR3PutU16(pSSM, pVirtio->virtqState[i].uAvailIdx); 1375 rc = SSMR3PutU16(pSSM, pVirtio->virtqState[i].uUsedIdx); 1376 rc = SSMR3PutMem(pSSM, pVirtio->virtqState[i].szVirtqName, 32); 1335 1377 } 1336 1378 … … 1389 1431 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueEnable[i]); 1390 1432 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueSize[i]); 1391 rc = SSMR3GetU16(pSSM, &pVirtio->virtq Proxy[i].uAvailIdx);1392 rc = SSMR3GetU16(pSSM, &pVirtio->virtq Proxy[i].uUsedIdx);1393 rc = SSMR3GetMem(pSSM, (void *)&pVirtio->virtq Proxy[i].szVirtqName, 32);1433 rc = SSMR3GetU16(pSSM, &pVirtio->virtqState[i].uAvailIdx); 1434 rc = SSMR3GetU16(pSSM, &pVirtio->virtqState[i].uUsedIdx); 1435 rc = SSMR3GetMem(pSSM, (void *)&pVirtio->virtqState[i].szVirtqName, 32); 1394 1436 } 1395 1437 } -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80683 r80762 38 38 #define VIRTQ_MAX_CNT 24 /**< Max queues we allow guest to create */ 39 39 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER 2 /**< VirtIO Notify Cap. MMIO config param */ 40 #define VIRTIOSCSI_REGION_MEM_IO 0 /**< BAR for MMIO (implementation specific) */ 41 #define VIRTIOSCSI_REGION_PORT_IO 1 /**< BAR for PORT I/O (impl specific) */ 42 #define VIRTIOSCSI_REGION_PCI_CAP 2 /**< BAR for VirtIO Cap. MMIO (impl specific) */ 40 #define VIRTIO_REGION_PCI_CAP 2 /**< BAR for VirtIO Cap. MMIO (impl specific) */ 43 41 44 42 #define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \ … … 47 45 virtioHexDump((pv), (cb), (base), (title)); \ 48 46 } while (0) 47 48 49 /** 50 * The following structure holds the pre-processed context of descriptor chain pulled from a virtio queue 51 * to conduct a transaction between the client of this virtio implementation and the guest VM's virtio driver. 52 * It contains the head index of the descriptor chain, the output data from the client that has been 53 * converted to a contiguous virtual memory and a physical memory scatter-gather buffer for use by by 54 * the virtio framework to complete the transaction in the final phase of round-trip processing. 55 * 56 * The client should not modify the contents of this buffer. The primary field of interest to the 57 * client is pVirtSrc, which contains the VirtIO "OUT" (to device) buffer from the guest. 58 * 59 * Typical use is, When the client (worker thread) detects available data on the queue, it pulls the 60 * next one of these descriptor chain structs off the queue using virtioQueueGet(), processes the 61 * virtual memory buffer pVirtSrc, produces result data to pass back to the guest driver and calls 62 * virtioQueuePut() to return the result data to the client. 63 */ 64 typedef struct VIRTIO_DESC_CHAIN 65 { 66 uint32_t uHeadIdx; /**< Head idx of associated desc chain */ 67 size_t cbVirtSrc; /**< Size of virt source buffer */ 68 void *pVirtSrc; /**< Virt mem buf holding out data from guest */ 69 size_t cbPhysDst; /**< Total size of dst buffer */ 70 PRTSGBUF pSgPhysDst; /**< Phys S/G buf to store result for guest */ 71 } VIRTIO_DESC_CHAIN_T, *PVIRTIO_DESC_CHAIN_T, **PPVIRTIO_DESC_CHAIN_T; 49 72 50 73 /** … … 155 178 int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName); 156 179 157 158 /**159 * Get the features VirtIO is running withnow.160 *161 * @returns Features the guest driver has accepted, finalizing the operational features162 *163 */164 uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio);165 166 180 /** 167 181 * Detaches from queue and release resources … … 174 188 175 189 /** 176 * Get name of queue, by qIdx, assigned at virtioQueueAttach() 177 * 178 * @param hVirtio - Handle for VirtIO framework 179 * @param qIdx - Queue number 180 * 181 * @returns Success: Returns pointer to queue name 182 * Failure: Returns "<null>" (never returns NULL pointer). 183 */ 184 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx); 185 186 /** 187 * Removes descriptor chain from avail ring of indicated queue and converts it to 188 * scatter/gather buffer (whose segments contain guest phys. data pointers) 189 * 190 * @param hVirtio - Handle for VirtIO framework 191 * @param qIdx - Queue number 192 * @param ppInSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 193 * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 194 * 195 * @returns status VINF_SUCCESS - Success 196 * VERR_INVALID_STATE - VirtIO not in ready state 197 */ 198 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs); 199 200 /** 201 * Same as virtioQueueGet() but leaves the item on the avail ring of the queue. 202 * 203 * @param hVirtio - Handle for VirtIO framework 204 * @param qIdx - Queue number 205 * @param ppInSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 206 * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF 207 * 208 * @returns VINF_SUCCESS - Success 209 * VERR_INVALID_STATE - VirtIO not in ready state 210 * VERR_NOT_AVAILABLE - Queue is empty 211 */ 212 int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs); 213 214 /** 215 * Writes a scatter/gather buffer (whose segments point to virtual memory) to next 216 * available descriptor chain (consisting of segments pointing to guest phys. memory), 217 * for the indicated virtq. The data won't be seen by the guest until the next 218 * client call to virtioQueueSync(), which puts aforementioned descriptor 219 * chain's head index on the indicated virtq's used ring (see VirtIO 1.0 220 * specification, Section 2.4 "Virtqueues"). 221 * 222 * @param hVirtio - Handle for VirtIO framework 223 * @param qIdx - Queue number 224 * @param pSgBuf - Caller's sgbuf of one or more virtual memory segments 225 * to write to the queue. This is useful because some kinds 226 * of transactions involve variable length subcomponents 227 * whose size can only be known near the time of writing. 228 * @parame fFence - If set put up copy fence (memory barrier) after 229 * copying to guest phys. mem. 230 * 231 * @returns VINF_SUCCESS - Success 232 * VERR_INVALID_STATE - VirtIO not in ready state 233 * VERR_NOT_AVAILABLE - Queue is empty 234 */ 235 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgBuf, bool fFence); 190 * Removes descriptor chain from avail ring of indicated queue and converts the descriptor 191 * chain into its OUT (to device) and IN to guest components. Additionally it converts 192 * the OUT desc chain data to a contiguous virtual memory buffer for easy consumption 193 * by the caller. The caller must return the descriptor chain pointer via virtioQueuePut() 194 * and then call virtioQueueSync() at some point to return the data to the guest and 195 * complete the transaction. 196 * 197 * @param hVirtio - Handle for VirtIO framework 198 * @param qIdx - Queue number 199 * @param fRemove - flags whether to remove desc chain from queue (false = peek) 200 * @param ppDescChain - Address to store pointer to descriptor chain that contains the 201 * pre-processed transaction information pulled from the virtq. 202 * 203 * @returns status VINF_SUCCESS - Success 204 * VERR_INVALID_STATE - VirtIO not in ready state 205 */ 206 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove); 207 208 209 /** 210 * Returns data to the guest to complete a transaction initiated by virtQueueGet(). 211 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments 212 * and a pointer to the descriptor chain context originally derived from the pulled 213 * queue entry, and this function will put write the virtual memory s/g buffer into the 214 * guest's physical memory free the descriptor chain. The caller handles the freeing 215 * (as needed) of the virtual memory buffer. 216 * 217 * NOTE: This does a write-ahead to the used ring of the guest's queue. 218 * The data written won't be seen by the guest until the next call to virtioQueueSync() 219 * 220 * 221 * @param hVirtio - Handle for VirtIO framework 222 * @param qIdx - Queue number 223 * 224 * @param pSgVirtReturn - Points toscatter-gather buffer of virtual memory segments 225 the caller is returning to the guest. 226 * 227 * @param pDescChain - This contains the context of the scatter-gather buffer 228 * originally pulled from the queue. 229 * 230 * @parame fFence - If true, put up copy fence (memory barrier) after 231 * copying to guest phys. mem. 232 * 233 * @returns VINF_SUCCESS - Success 234 * VERR_INVALID_STATE - VirtIO not in ready state 235 * VERR_NOT_AVAILABLE - Queue is empty 236 */ 237 238 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PRTSGBUF pSgVirtReturn, 239 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence); 240 236 241 237 242 /** … … 297 302 void virtioPropagateResumeNotification(VIRTIOHANDLE hVirtio); 298 303 304 /** 305 * Get name of queue, by qIdx, assigned at virtioQueueAttach() 306 * 307 * @param hVirtio - Handle for VirtIO framework 308 * @param qIdx - Queue number 309 * 310 * @returns Success: Returns pointer to queue name 311 * Failure: Returns "<null>" (never returns NULL pointer). 312 */ 313 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx); 314 315 /** 316 * Get the features VirtIO is running withnow. 317 * 318 * @returns Features the guest driver has accepted, finalizing the operational features 319 * 320 */ 321 uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio); 299 322 300 323 -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r80718 r80762 85 85 86 86 /** 87 * IN/OUT Descriptor chains descriptor chain associated with one element of virtq avail ring represented88 * as respective arrays of SG segments.89 */90 typedef struct VIRTQ_DESC_CHAIN /**< Describes a single queue element */91 {92 RTSGSEG aSegsIn[VIRTQ_MAX_SIZE]; /**< List of segments to write to guest */93 RTSGSEG aSegsOut[VIRTQ_MAX_SIZE]; /**< List of segments read from guest */94 uint32_t uHeadIdx; /**< Index at head desc (source of seg arrays) */95 uint32_t cSegsIn; /**< Count of segments in aSegsIn[] */96 uint32_t cSegsOut; /**< Count of segments in aSegsOut[] */97 } VIRTQ_DESC_CHAIN_T, *PVIRTQ_DESC_CHAIN_T;98 99 /**100 87 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification) 101 88 */ 102 typedef struct VIRTQ_PROXY 103 { 104 RTSGBUF inSgBuf; /**< host-to-guest buffers */ 105 RTSGBUF outSgBuf; /**< guest-to-host buffers */ 89 typedef struct VIRTQSTATE 90 { 106 91 const char szVirtqName[32]; /**< Dev-specific name of queue */ 107 92 uint16_t uAvailIdx; /**< Consumer's position in avail ring */ 108 93 uint16_t uUsedIdx; /**< Consumer's position in used ring */ 109 94 bool fEventThresholdReached; /**< Don't lose track while queueing ahead */ 110 PVIRTQ_DESC_CHAIN_T pDescChain; /**< Per-queue s/g data. */ 111 } VIRTQ_PROXY_T, *PVIRTQ_PROXY_T; 95 } VIRTQSTATE, *PVIRTQSTATE; 112 96 113 97 /** … … 191 175 uint8_t uConfigGeneration; /**< (MMIO) Device config sequencer HOST */ 192 176 193 VIRTQ _PROXY_T virtqProxy[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */177 VIRTQSTATE virtqState[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */ 194 178 VIRTIOCALLBACKS virtioCallbacks; /**< Callback vectors to client */ 195 179 … … 378 362 DECLINLINE(bool) virtqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx) 379 363 { 380 return virtioReadAvailRingIdx(pVirtio, qIdx) == pVirtio->virtq Proxy[qIdx].uAvailIdx;364 return virtioReadAvailRingIdx(pVirtio, qIdx) == pVirtio->virtqState[qIdx].uAvailIdx; 381 365 } 382 366
Note:
See TracChangeset
for help on using the changeset viewer.