Changeset 80340 in vbox for trunk/src/VBox/Devices/VirtIO
- Timestamp:
- Aug 19, 2019 7:43:37 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
r80308 r80340 35 35 36 36 #ifdef LOG_ENABLED 37 # define QUEUENAME(s, q) (q-> pcszName)37 # define QUEUENAME(s, q) (q->szName) 38 38 #endif 39 39 … … 93 93 } 94 94 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 { 95 int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName) 96 { 97 LogFunc(("%s\n", pcszName)); 106 98 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 107 PVIRTQ_ SHADOW_T pVirtqShadow = &(pVirtio->virtqShadow[qIdx]);99 PVIRTQ_PROXY_T pVirtqProxy = &(pVirtio->virtqProxy[qIdx]); 108 100 if (pVirtio->uQueueEnable[qIdx]) 109 101 { 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 118 PVIRTQ_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; 118 128 } 119 129 120 130 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx) 121 131 { 122 return (const char *)((PVIRTIOSTATE)hVirtio)->virtqShadow[qIdx].pcszName;123 }124 125 126 bool virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)127 {128 132 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 139 int 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); 130 148 131 149 if (virtioQueueIsEmpty(pVirtio, qIdx)) 132 return false;150 return VERR_NOT_AVAILABLE; 133 151 134 152 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; 138 157 } 139 158 … … 141 160 { 142 161 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 165 int 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 */ 171 int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove) 172 { 158 173 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); 166 179 167 180 if (vqIsEmpty(pVirtio, qIdx)) 168 return false;181 return VERR_NOT_AVAILABLE; 169 182 170 183 pBufVec->cSegsIn = pBufVec->cSegsOut = 0; 171 184 172 Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pVirtq Shadow->pcszName, pVirtqShadow->uAvailIdx));185 Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pVirtqProxy->szName, pVirtqProxy->uAvailIdx)); 173 186 174 187 uint16_t uDescIdx; 175 pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqShadow->uAvailIdx);188 // pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx); 176 189 177 190 if (fRemove) 178 pVirtq Shadow->uAvailIdx++;191 pVirtqProxy->uAvailIdx++; 179 192 180 193 VIRTQ_DESC_T desc; … … 187 200 * several descriptors into a loop. Since there is no legitimate way to get a sequences of 188 201 * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}), 189 * the following aborts I/O if bre ech 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. 190 203 */ 191 204 if (pBufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE) … … 207 220 RT_UNTRUSTED_VALIDATED_FENCE(); 208 221 209 vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);222 // vqReadDesc(pVirtio, qIdx, uDescIdx, &desc); 210 223 if (desc.fFlags & VIRTQ_DESC_F_WRITE) 211 224 { 212 225 Log2Func(("%s: %s IN seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio), 213 pVirtq Shadow->pcszName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb));226 pVirtqProxy->szName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb)); 214 227 pSeg = &(pBufVec->aSegsIn[pBufVec->cSegsIn++]); 215 228 } … … 217 230 { 218 231 Log2Func(("%s: %s IN seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio), 219 pVirtq Shadow->pcszName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb));232 pVirtqProxy->szName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb)); 220 233 pSeg = &(pBufVec->aSegsOut[pBufVec->cSegsOut++]); 221 234 } … … 229 242 230 243 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 */ 250 int virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx) 251 { 252 Assert(qIdx < sizeof(VIRTQ_PROXY_T)); 253 244 254 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); 246 260 247 261 Log2Func(("%s: %s desc_idx=%u acb=%u\n", 248 INSTANCE(pVirtio), pVirtq Shadow->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; 251 265 252 266 for (uint32_t iSeg = 0; iSeg < pBufVec->cSegsIn && cbRemaining > 0; ++iSeg) … … 256 270 cbSegLen = cbRemaining; 257 271 258 Assert(pBufVec->aSegsIn[iSeg].pv != NULL);259 272 260 273 if (pBufVec->aSegsIn[iSeg].pv != NULL) 261 274 { 262 275 Log2Func(("%s: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", 263 INSTANCE(pVirtio), pVirtq Shadow->pcszName,264 pVirtq Shadow->uUsedIdx, iSeg,276 INSTANCE(pVirtio), pVirtqProxy->szName, 277 pVirtqProxy->uUsedIdx, iSeg, 265 278 (void *)pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, 266 279 pBufVec->aSegsIn[iSeg].cb, cbSegLen)); … … 274 287 uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx); 275 288 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 */ 300 int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx) 301 { 302 Assert(qIdx < sizeof(VIRTQ_PROXY_T)); 303 290 304 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); 292 309 293 310 uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx); 294 311 Log2Func(("%s: %s old_used_idx=%u new_used_idx=%u\n", 295 INSTANCE(pVirtio), uDescIdx, pVirtq Shadow->uUsedIdx));296 297 vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtq Shadow->uUsedIdx);312 INSTANCE(pVirtio), uDescIdx, pVirtqProxy->uUsedIdx)); 313 314 vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx); 298 315 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 v qDeviceNotified(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 */ 321 static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx) 305 322 { 306 323 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)); 309 327 310 328 /** Inform client */ 311 pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, qIdx);329 pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, pVirtio->pClientContext, qIdx); 312 330 } 313 331 … … 316 334 * the specified virtq, depending on the interrupt configuration of the device 317 335 * and depending on negotiated and realtime constraints flagged by the guest driver. 318 * See VirtIO 1.0 specification (se e section 2.4.7).336 * See VirtIO 1.0 specification (section 2.4.7). 319 337 */ 320 338 static void vqNotifyDriver(PVIRTIOSTATE pVirtio, uint16_t qIdx) 321 339 { 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")); 329 344 330 345 LogFlowFunc(("%s: %s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n", 331 INSTANCE(pVirtio), pVirtq Shadow->pcszName, vqReadAvailFlags(pVirtio, qIdx),346 INSTANCE(pVirtio), pVirtqProxy->szName, vqReadAvailFlags(pVirtio, qIdx), 332 347 pVirtio->uDriverFeatures, vqIsEmpty(pVirtio, qIdx) ? "" : "not ")); 333 348 … … 335 350 { 336 351 if ( pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX 337 && pVirtq Shadow->fEventThresholdReached)352 && pVirtqProxy->fEventThresholdReached) 338 353 { 339 354 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT); 340 pVirtq Shadow->fEventThresholdReached = false;355 pVirtqProxy->fEventThresholdReached = false; 341 356 } 342 357 else 343 358 { 359 /** If guest driver hasn't suppressed interrupts, do so */ 344 360 if (!(vqReadUsedFlags(pVirtio, qIdx) & VIRTQ_AVAIL_F_NO_INTERRUPT)) 345 361 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT); … … 353 369 354 370 /** 355 *356 371 * NOTE: The consumer (PDM device) must call this function to 'forward' a relocation call. 357 372 * 358 373 * Device relocation callback. 359 *360 374 * 361 375 * When this callback is called the device instance data, and if the … … 413 427 } 414 428 415 416 417 static void vqReset(PVIRTIOSTATE pVirtio, uint16_t qIdx) 418 { 419 PVIRTQ_SHADOW_T pVirtQ = &pVirtio->virtqShadow[qIdx]; 429 static void virtioResetQueue(PVIRTIOSTATE pVirtio, uint16_t qIdx) 430 { 431 PVIRTQ_PROXY_T pVirtQ = &pVirtio->virtqProxy[qIdx]; 420 432 pVirtQ->uAvailIdx = 0; 421 433 pVirtQ->uUsedIdx = 0; … … 442 454 pVirtio->uNumQueues = VIRTQ_MAX_CNT; 443 455 for (uint16_t qIdx = 0; qIdx < pVirtio->uNumQueues; qIdx++) 444 v qReset(pVirtio, qIdx);456 virtioResetQueue(pVirtio, qIdx); 445 457 } 446 458 … … 451 463 void virtioResetAll(VIRTIOHANDLE hVirtio) 452 464 { 465 LogFunc(("VIRTIO RESET REQUESTED!!!\n")); 453 466 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 454 467 pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET; … … 469 482 470 483 /** Let the client know */ 471 pVirtio->virtioCallbacks.pfnVirtioStatusChanged((VIRTIOHANDLE)pVirtio, false);484 pVirtio->virtioCallbacks.pfnVirtioStatusChanged((VIRTIOHANDLE)pVirtio, pVirtio->pClientContext, false); 472 485 virtioResetDevice(pVirtio); 473 486 } … … 490 503 { 491 504 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")); 493 506 else /* Guest READ pCommonCfg->uDeviceFeatures */ 494 507 { … … 508 521 break; 509 522 default: 510 Log 2Func(("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", 511 524 pVirtio->uDeviceFeaturesSelect)); 512 525 return VERR_ACCESS_DENIED; … … 531 544 break; 532 545 default: 533 Log 2Func(("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", 534 547 pVirtio->uDriverFeaturesSelect)); 535 548 return VERR_ACCESS_DENIED; … … 553 566 break; 554 567 default: 555 Log 2Func(("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", 556 569 pVirtio->uDriverFeaturesSelect)); 557 570 return VERR_ACCESS_DENIED; … … 589 602 bool fWasOkay = pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK; 590 603 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); 593 606 pVirtio->uPrevDeviceStatus = pVirtio->uDeviceStatus; 594 607 } … … 677 690 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap, fDevSpecific); 678 691 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysCommonCfg, pVirtio->pCommonCfgCap, fCommonCfg); 679 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap, pVirtio->pIsrCap, fIsr Cap);692 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap, pVirtio->pIsrCap, fIsr); 680 693 681 694 if (fDevSpecific) 682 695 { 683 uint32_t u DevSpecificDataOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap;696 uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap; 684 697 /** 685 * Callback to client to manage device-specific configuration and changes to it.698 * Callback to client to manage device-specific configuration. 686 699 */ 687 rc = pVirtio->virtioCallbacks.pfnVirtioDevCapRead(pDevIns, uDevSpecificDataOffset, pv, cb); 700 rc = pVirtio->virtioCallbacks.pfnVirtioDevCapRead(pDevIns, uOffset, pv, cb); 701 688 702 /** 689 * A nytime any part of the device-specific configuration (which our client maintains) is read690 * i t needs to be checked to see if it changed since the last time any part was read, in703 * 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 691 705 * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1) 692 706 */ 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 700 712 if (pVirtio->fGenUpdatePending || fDevSpecificFieldChanged) 701 713 { 702 if (fDevSpecificFieldChanged)703 Log2Func(("Dev specific config field changed since last read, gen++ = %d\n",704 pVirtio->uConfigGeneration));705 else706 Log2Func(("Config generation pending flag set, gen++ = %d\n",707 pVirtio->uConfigGeneration));708 714 ++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>" : "")); 709 719 pVirtio->fGenUpdatePending = false; 710 720 } … … 713 723 if (fCommonCfg) 714 724 { 715 uint32_t u CommonCfgDataOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg;716 virtioCommonCfgAccessed(pVirtio, 0 /* fWrite */, u CommonCfgDataOffset, cb, pv);725 uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg; 726 virtioCommonCfgAccessed(pVirtio, 0 /* fWrite */, uOffset, cb, pv); 717 727 } 718 728 else 719 if (fIsr Cap)729 if (fIsr && cb == sizeof(uint8_t)) 720 730 { 721 731 *(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, 725 734 !!(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG))); 726 735 pVirtio->uISR = 0; /** VirtIO specification requires reads of ISR to clear it */ … … 753 762 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap, fDevSpecific); 754 763 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysCommonCfg, pVirtio->pCommonCfgCap, fCommonCfg); 755 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap, pVirtio->pIsrCap, fIsr Cap);756 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysNotifyCap, pVirtio->pNotifyCap, fNotify Cap);764 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap, pVirtio->pIsrCap, fIsr); 765 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysNotifyCap, pVirtio->pNotifyCap, fNotify); 757 766 758 767 if (fDevSpecific) 759 768 { 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); 762 774 } 763 775 else 764 776 if (fCommonCfg) 765 777 { 766 uint32_t u CommonCfgDataOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg;767 virtioCommonCfgAccessed(pVirtio, 1 /* fWrite */, u CommonCfgDataOffset, cb, pv);778 uint32_t uOffset = GCPhysAddr - pVirtio->pGcPhysCommonCfg; 779 virtioCommonCfgAccessed(pVirtio, 1 /* fWrite */, uOffset, cb, pv); 768 780 } 769 781 else 770 if (fIsr Cap)782 if (fIsr && cb == sizeof(uint8_t)) 771 783 { 772 784 pVirtio->uISR = *(uint8_t *)pv; 773 Log2Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg in nterrupt: %d)\n",785 Log2Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg interrupt: %d)\n", 774 786 pVirtio->uISR & 0xff, 775 787 pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT, … … 777 789 } 778 790 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)) 780 793 { 781 794 uint32_t uNotifyBaseOffset = GCPhysAddr - pVirtio->pGcPhysNotifyCap; 782 795 uint16_t qIdx = uNotifyBaseOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER; 783 uint16_t u NotifiedIdx = *(uint16_t *)pv;784 v qDeviceNotified(pVirtio, qIdx, uNotifiedIdx);796 uint16_t uAvailDescIdx = *(uint16_t *)pv; 797 virtioQueueNotified(pVirtio, qIdx, uAvailDescIdx); 785 798 } 786 799 else … … 825 838 pVirtio->pGcPhysNotifyCap = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset; 826 839 pVirtio->pGcPhysIsrCap = GCPhysAddress + pVirtio->pIsrCap->uOffset; 827 if (pVirtio->p DevSpecificCap)840 if (pVirtio->pPrevDevSpecificCfg) 828 841 pVirtio->pGcPhysDeviceCap = GCPhysAddress + pVirtio->pDeviceCap->uOffset; 829 842 } … … 948 961 * 949 962 * @param pDevIns Device instance data 963 * @param pClientContext Opaque client context (such as state struct, ...) 950 964 * @param pVirtio Device State 951 965 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure … … 960 974 * @param ssmLoadExecCallback Client handler for SSM load exec 961 975 * @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. 963 978 */ 964 979 int virtioConstruct(PPDMDEVINS pDevIns, 980 void *pClientContext, 965 981 VIRTIOHANDLE *phVirtio, 966 982 PVIRTIOPCIPARAMS pPciParams, … … 975 991 PFNSSMDEVLOADEXEC ssmLoadExecCallback, 976 992 PFNSSMDEVLOADDONE ssmLoadDoneCallback, 977 uint16_t cbDevSpecificC ap,978 void *pDevSpecificC ap)993 uint16_t cbDevSpecificCfg, 994 void *pDevSpecificCfg) 979 995 { 980 996 981 997 int rc = VINF_SUCCESS; 982 998 983 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAlloc(sizeof(VIRTIOSTATE)); 999 1000 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAllocZ(sizeof(VIRTIOSTATE)); 984 1001 if (!pVirtio) 985 1002 { … … 987 1004 return VERR_NO_MEMORY; 988 1005 } 1006 1007 pVirtio->pClientContext = pClientContext; 989 1008 990 1009 /** … … 1002 1021 pVirtio->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1003 1022 pVirtio->uDeviceStatus = 0; 1004 pVirtio->cbDevSpecificC ap = cbDevSpecificCap;1005 pVirtio->pDevSpecificC ap = pDevSpecificCap;1006 1007 pVirtio->pPrevDevSpecificC ap = RTMemAlloc(cbDevSpecificCap);1008 if (!pVirtio->pPrevDevSpecificC ap)1023 pVirtio->cbDevSpecificCfg = cbDevSpecificCfg; 1024 pVirtio->pDevSpecificCfg = pDevSpecificCfg; 1025 1026 pVirtio->pPrevDevSpecificCfg = RTMemAlloc(cbDevSpecificCfg); 1027 if (!pVirtio->pPrevDevSpecificCfg) 1009 1028 { 1010 1029 RTMemFree(pVirtio); … … 1013 1032 } 1014 1033 1015 memcpy(pVirtio->pPrevDevSpecificC ap, pVirtio->pDevSpecificCap, cbDevSpecificCap);1034 memcpy(pVirtio->pPrevDevSpecificCfg, pVirtio->pDevSpecificCfg, cbDevSpecificCfg); 1016 1035 pVirtio->virtioCallbacks.pfnVirtioDevCapRead = devCapReadCallback; 1017 1036 pVirtio->virtioCallbacks.pfnVirtioDevCapWrite = devCapWriteCallback; … … 1108 1127 pVirtio->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER; 1109 1128 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 */ 1111 1135 pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext]; 1112 1136 pCfg->uCfgType = VIRTIO_PCI_CAP_ISR_CFG; … … 1116 1140 pCfg->uBar = VIRTIOSCSI_REGION_PCI_CAP; 1117 1141 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); 1119 1143 cbRegion += pCfg->uLength; 1120 1144 pVirtio->pIsrCap = pCfg; … … 1124 1148 * by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write 1125 1149 * 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. */ 1127 1152 1128 1153 pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext]; … … 1130 1155 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR; 1131 1156 pCfg->uCapLen = sizeof(VIRTIO_PCI_CFG_CAP_T); 1132 pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificC ap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;1157 pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCfg) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1133 1158 pCfg->uBar = 0; 1134 1159 pCfg->uOffset = 0; … … 1137 1162 pVirtio->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg; 1138 1163 1139 if (pVirtio->pDevSpecificC ap)1164 if (pVirtio->pDevSpecificCfg) 1140 1165 { 1141 1166 /** Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the … … 1149 1174 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength; 1150 1175 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 4); 1151 pCfg->uLength = cbDevSpecificC ap;1176 pCfg->uLength = cbDevSpecificCfg; 1152 1177 cbRegion += pCfg->uLength; 1153 1178 pVirtio->pDeviceCap = pCfg; … … 1180 1205 if (RT_FAILURE(rc)) 1181 1206 { 1182 RTMemFree(pVirtio->pPrevDevSpecificC ap);1207 RTMemFree(pVirtio->pPrevDevSpecificCfg); 1183 1208 RTMemFree(pVirtio); 1184 1209 return PDMDEV_SET_ERROR(pDevIns, rc, … … 1194 1219 # ifdef DEBUG 1195 1220 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 } 1221 static 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 } 1283 1268 # endif 1284 1269 #endif … … 1303 1288 rc = SSMR3PutU32(pSSM, pVirtio->uDriverFeaturesSelect); 1304 1289 rc = SSMR3PutU32(pSSM, pVirtio->uNumQueues); 1305 rc = SSMR3PutU32(pSSM, pVirtio->cbDevSpecificC ap);1290 rc = SSMR3PutU32(pSSM, pVirtio->cbDevSpecificCfg); 1306 1291 rc = SSMR3PutU64(pSSM, pVirtio->uDeviceFeatures); 1307 1292 rc = SSMR3PutU64(pSSM, pVirtio->uDriverFeatures); 1308 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->pDevSpecificC ap);1293 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->pDevSpecificCfg); 1309 1294 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->virtioCallbacks.pfnVirtioStatusChanged); 1310 1295 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->virtioCallbacks.pfnVirtioQueueNotified); … … 1332 1317 rc = SSMR3PutU16(pSSM, pVirtio->uQueueEnable[i]); 1333 1318 rc = SSMR3PutU16(pSSM, pVirtio->uQueueSize[i]); 1334 rc = SSMR3PutU16(pSSM, pVirtio->virtq Shadow[i].uAvailIdx);1335 rc = SSMR3PutU16(pSSM, pVirtio->virtq Shadow[i].uUsedIdx);1336 rc = SSMR3PutMem(pSSM, pVirtio->virtq Shadow[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); 1337 1322 } 1338 1323 … … 1362 1347 rc = SSMR3GetU32(pSSM, &pVirtio->uDriverFeaturesSelect); 1363 1348 rc = SSMR3GetU32(pSSM, &pVirtio->uNumQueues); 1364 rc = SSMR3GetU32(pSSM, &pVirtio->cbDevSpecificC ap);1349 rc = SSMR3GetU32(pSSM, &pVirtio->cbDevSpecificCfg); 1365 1350 rc = SSMR3GetU64(pSSM, &pVirtio->uDeviceFeatures); 1366 1351 rc = SSMR3GetU64(pSSM, &pVirtio->uDriverFeatures); 1367 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->pDevSpecificC ap);1352 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->pDevSpecificCfg); 1368 1353 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioStatusChanged); 1369 1354 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioQueueNotified); … … 1391 1376 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueEnable[i]); 1392 1377 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueSize[i]); 1393 rc = SSMR3GetU16(pSSM, &pVirtio->virtq Shadow[i].uAvailIdx);1394 rc = SSMR3GetU16(pSSM, &pVirtio->virtq Shadow[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); 1396 1381 } 1397 1382 } -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80306 r80340 34 34 * TEMPORARY NOTE: Some of these values are experimental during development and will likely change. 35 35 */ 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 */ 37 38 #define VIRTQ_MAX_CNT 24 /**< Max queues we allow guest to create */ 39 #define VIRTQ_DESC_MAX_SIZE (2 * 1024 * 1024) 38 40 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER 2 /**< VirtIO Notify Cap. MMIO config param */ 39 #define VIRTQ_DESC_MAX_SIZE (2 * 1024 * 1024)40 41 #define VIRTIOSCSI_REGION_MEM_IO 0 /**< BAR for MMIO (implementation specific) */ 41 42 #define VIRTIOSCSI_REGION_PORT_IO 1 /**< BAR for PORT I/O (impl specific) */ 42 43 #define VIRTIOSCSI_REGION_PCI_CAP 2 /**< BAR for VirtIO Cap. MMIO (impl specific) */ 43 44 44 typedef struct VIRTQ_SEG /**< Describes one segment of a buffer vector */ 45 45 { … … 49 49 } VIRTQ_SEG_T; 50 50 51 typedef struct VIRTQ_BUF_VECTOR /**< Scatter/gather buffer vector */51 typedef struct VIRTQ_BUF_VECTOR /**< Scatter/gather buffer vector */ 52 52 { 53 53 uint32_t uDescIdx; /**< Desc at head of this vector list */ … … 81 81 * @param hVirtio Handle to VirtIO framework 82 82 * @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 */ 85 typedef DECLCALLBACK(void) FNVIRTIOSTATUSCHANGED(VIRTIOHANDLE hVirtio, void *pClient, bool fDriverOk); 85 86 typedef FNVIRTIOSTATUSCHANGED *PFNVIRTIOSTATUSCHANGED; 86 87 … … 91 92 * @param hVirtio Handle to the VirtIO framework 92 93 * @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 */ 96 typedef DECLCALLBACK(void) FNVIRTIOQUEUENOTIFIED(VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx); 95 97 typedef FNVIRTIOQUEUENOTIFIED *PFNVIRTIOQUEUENOTIFIED; 96 98 … … 125 127 { 126 128 DECLCALLBACKMEMBER(void, pfnVirtioStatusChanged) 127 (VIRTIOHANDLE hVirtio, bool fDriverOk);129 (VIRTIOHANDLE hVirtio, void *pClient, bool fDriverOk); 128 130 DECLCALLBACKMEMBER(void, pfnVirtioQueueNotified) 129 (VIRTIOHANDLE hVirtio, uint16_t qIdx);131 (VIRTIOHANDLE hVirtio, void *pClient, uint16_t qIdx); 130 132 DECLCALLBACKMEMBER(int, pfnVirtioDevCapRead) 131 133 (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbRead); … … 144 146 /** @} */ 145 147 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 */ 165 int 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 */ 173 int 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 */ 183 PVIRTQ_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 */ 194 const 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 */ 206 int 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 */ 218 int 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 */ 232 int 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 */ 248 int 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 */ 259 bool virtioQueueIsEmpty (VIRTIOHANDLE hVirtio, uint16_t qIdx); 260 261 /** 262 * Request orderly teardown of VirtIO on host and guest 263 */ 264 void virtioResetAll(VIRTIOHANDLE hVirtio); 157 265 158 266 /** CLIENT MUST CALL ON RELOCATE CALLBACK! */ 159 void virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta);267 void virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta); 160 268 161 269 /** … … 163 271 * 164 272 * @param pDevIns Device instance data 273 * @param pClientContext Opaque client context (such as state struct) 165 274 * @param pVirtio Device State 166 275 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure … … 175 284 * @param ssmLoadExecCallback Client handler for SSM load exec 176 285 * @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 178 288 */ 179 289 int virtioConstruct(PPDMDEVINS pDevIns, 290 void *pClientContext, 180 291 VIRTIOHANDLE *phVirtio, 181 292 PVIRTIOPCIPARAMS pPciParams, … … 190 301 PFNSSMDEVLOADEXEC ssmLoadExecCallback, 191 302 PFNSSMDEVLOADDONE ssmLoadDoneCallback, 192 uint16_t cbDevSpecificC ap,193 void *pDevSpecificC ap);303 uint16_t cbDevSpecificCfg, 304 void *pDevSpecificCfg); 194 305 195 306 /** -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r80308 r80340 87 87 * Local implementation's usage context of a queue (e.g. not part of VirtIO specification) 88 88 */ 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; 89 typedef 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; 96 97 97 98 /** … … 135 136 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T; 136 137 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;139 138 140 139 /** … … 147 146 PDMPCIDEV dev; /**< PCI device */ 148 147 char szInstance[16]; /**< Instance name, e.g. "VIRTIOSCSI0" */ 148 void * pClientContext; /**< Client callback returned on callbacks */ 149 149 150 150 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3 */ … … 177 177 uint8_t uConfigGeneration; /**< (MMIO) Device config sequencer HOST */ 178 178 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 */ 180 180 VIRTIOCALLBACKS virtioCallbacks; /**< Callback vectors to client */ 181 181 … … 189 189 PVIRTIO_PCI_CAP_T pDeviceCap; /**< Pointer to struct in configuration area */ 190 190 191 uint32_t cbDevSpecificC ap; /**< Size of client's dev-specific config data */192 void *pDevSpecificC ap; /**< Pointer to client's struct */193 void *pPrevDevSpecificC ap; /**< 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 */ 194 194 bool fGenUpdatePending; /**< If set, update cfg gen after driver reads */ 195 195 uint8_t uPciCfgDataOff; … … 329 329 } 330 330 331 #define DRIVER_OK(pVirtio) (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 332 331 333 /** 332 334 * Internal queue operations … … 335 337 static int vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld); 336 338 static bool vqIsEmpty (PVIRTIOSTATE pVirtio, uint16_t qIdx); 337 static void vqReset (PVIRTIOSTATE pVirtio, uint16_t qIdx);338 339 static void vqReadDesc (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc); 339 340 static uint16_t vqReadAvailRingDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx); … … 356 357 DECLINLINE(bool) vqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx) 357 358 { 358 return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->virtq Shadow->uAvailIdx;359 return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->virtqProxy->uAvailIdx; 359 360 } 360 361 … … 511 512 } 512 513 513 static void vqReset (PVIRTIOSTATE pVirtio, uint16_t qIdx); 514 static void vqDeviceNotified (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx); 514 static void virtioResetQueue (PVIRTIOSTATE pVirtio, uint16_t qIdx); 515 515 static void vqNotifyDriver (PVIRTIOSTATE pVirtio, uint16_t qIdx); 516 516 static int virtioRaiseInterrupt (PVIRTIOSTATE pVirtio, uint8_t uCause); 517 517 static void virtioLowerInterrupt (PVIRTIOSTATE pVirtio); 518 static void virtioQueueNotified (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx); 518 519 static int virtioCommonCfgAccessed (PVIRTIOSTATE pVirtio, int fWrite, off_t uOffset, unsigned cb, void const *pv); 519 520 static void virtioGuestResetted (PVIRTIOSTATE pVirtio);
Note:
See TracChangeset
for help on using the changeset viewer.