Changeset 80219 in vbox for trunk/src/VBox/Devices/VirtIO
- Timestamp:
- Aug 12, 2019 7:23:05 AM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 132668
- Location:
- trunk/src/VBox/Devices/VirtIO
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r80201 r80219 27 27 #include <iprt/uuid.h> 28 28 #include <iprt/mem.h> 29 #include <iprt/assert.h> 29 30 #include <VBox/vmm/pdmdev.h> 30 31 #include "Virtio_1_0_impl.h" 31 32 #include "Virtio_1_0.h" 32 33 33 #define INSTANCE(pState) pState->szInstance 34 #define IFACE_TO_STATE(pIface, ifaceName) ((VIRTIOSTATE *)((char*)(pIface) - RT_UOFFSETOF(VIRTIOSTATE, ifaceName))) 35 36 #define H2P(hVirtio) ((PVIRTIOSTATE)(hVirtio)) 34 #define INSTANCE(pVirtio) pVirtio->szInstance 37 35 38 36 #ifdef LOG_ENABLED … … 43 41 * Formats the logging of a memory-mapped I/O input or output value 44 42 * 45 * @param pszFunc - To avoid displaying this function's name via __FUNCTION__ or Log Func()43 * @param pszFunc - To avoid displaying this function's name via __FUNCTION__ or Log2Func() 46 44 * @param pszMember - Name of struct member 47 45 * @param pv - pointer to value … … 52 50 * @param idx - The index if fHasIndex 53 51 */ 54 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, const void *pv, uint32_t cb, 55 uint32_t uOffset, bool fWrite, bool fHasIndex, uint32_t idx) 56 { 57 58 #define FMTHEX(fmtout, val, cNybs) \ 59 fmtout[cNybs] = '\0'; \ 60 for (uint8_t i = 0; i < cNybs; i++) \ 61 fmtout[(cNybs - i) -1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf]; 52 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, size_t uMemberSize, 53 const void *pv, uint32_t cb, uint32_t uOffset, bool fWrite, 54 bool fHasIndex, uint32_t idx) 55 { 56 57 #define FMTHEX(fmtout, val, cNybbles) \ 58 fmtout[cNybbles] = '\0'; \ 59 for (uint8_t i = 0; i < cNybbles; i++) \ 60 fmtout[(cNybbles - i) - 1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf]; 62 61 63 62 #define MAX_STRING 64 … … 73 72 memcpy((char *)&val, pv, cb); 74 73 FMTHEX(pszFormattedVal, val, cb * 2); 75 if (uOffset != 0 ) /* display bounds if partial member access */74 if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */ 76 75 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]", 77 76 pszMember, pszIdx, uOffset, uOffset + cb - 1); … … 81 80 uint32_t first = 0; 82 81 for (uint8_t i = 0; i < sizeof(pszDepiction); i++) 83 if (pszDepiction[i] == ' ' && first++ != 0)82 if (pszDepiction[i] == ' ' && first++) 84 83 pszDepiction[i] = '.'; 85 84 Log(("%s: Guest %s %s 0x%s\n", \ … … 94 93 } 95 94 96 97 void virtQueueReadDesc(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx, PVIRTQ_DESC_T pDesc) 98 { 99 //Log(("%s virtQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx)); 100 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 101 pVirtQ->pGcPhysVirtqDescriptors + sizeof(VIRTQ_DESC_T) * (idx % pVirtQ->cbQueue), 102 pDesc, sizeof(VIRTQ_DESC_T)); 103 } 104 105 uint16_t virtQueueReadAvail(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx) 106 { 107 uint16_t tmp; 108 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 109 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[idx % pVirtQ->cbQueue]), 110 &tmp, sizeof(tmp)); 111 return tmp; 112 } 113 114 uint16_t virtQueueReadAvailFlags(PVIRTIOSTATE pState, PVIRTQ pVirtQ) 115 { 116 uint16_t tmp; 117 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 118 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags), 119 &tmp, sizeof(tmp)); 120 return tmp; 121 } 122 123 uint16_t virtQueueReadUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ) 124 { 125 uint16_t tmp; 126 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 127 pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx), 128 &tmp, sizeof(tmp)); 129 return tmp; 130 } 131 132 void virtQueueWriteUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint16_t u16Value) 133 { 134 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 135 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uIdx), 136 &u16Value, sizeof(u16Value)); 137 } 138 139 void virtQueueWriteUsedElem(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint32_t idx, uint32_t id, uint32_t uLen) 140 { 141 142 RT_NOREF5(pState, pVirtQ, idx, id, uLen); 143 /* PK TODO: Adapt to VirtIO 1.0 144 VIRTQ_USED_ELEM_T elem; 145 146 elem.id = id; 147 elem.uLen = uLen; 148 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 149 pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF_DYN(VIRTQ_USED_T, ring[idx % pVirtQ->cbQueue]), 150 &elem, sizeof(elem)); 151 */ 152 } 153 154 void virtQueueSetNotification(PVIRTIOSTATE pState, PVIRTQ pVirtQ, bool fEnabled) 155 { 156 RT_NOREF3(pState, pVirtQ, fEnabled); 157 158 /* PK TODO: Adapt to VirtIO 1.0 159 uint16_t tmp; 160 161 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 162 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags), 163 &tmp, sizeof(tmp)); 164 165 if (fEnabled) 166 tmp &= ~ VIRTQ_USED_T_F_NO_NOTIFY; 167 else 168 tmp |= VIRTQ_USED_T_F_NO_NOTIFY; 169 170 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 171 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags), 172 &tmp, sizeof(tmp)); 173 */ 174 } 175 176 bool virtQueueSkip(PVIRTIOSTATE pState, PVQUEUE pQueue) 177 { 178 179 RT_NOREF2(pState, pQueue); 180 /* PK TODO Adapt to VirtIO 1.0 181 if (virtQueueIsEmpty(pState, pQueue)) 95 /** 96 * This is called when MMIO handler detects guest write to a virtq's notification address 97 */ 98 static void vqNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx) 99 { 100 Assert(uNotifyIdx == qIdx); 101 PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx]; 102 Log2Func(("%s: %s notified\n", INSTANCE(pVirtio), pQueueContext->pcszName)); 103 104 /** inform client */ 105 pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, qIdx); 106 } 107 108 static void vqNotify(PVIRTIOSTATE pVirtio, uint16_t qIdx) 109 { 110 PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx]; 111 112 bool fEmpty = vqIsEmpty(pVirtio, qIdx); 113 bool fAvailFlags = vqReadAvailFlags(pVirtio, qIdx); 114 115 LogFlowFunc(("%s: %s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n", 116 INSTANCE(pVirtio), pQueueContext->pcszName, fAvailFlags, pVirtio->uDriverFeatures, fEmpty ? "" : "not ")); 117 118 if (!(fAvailFlags & VIRTQ_AVAIL_F_NO_INTERRUPT)) 119 { 120 int rc = virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT); 121 if (RT_FAILURE(rc)) 122 Log(("%s virtioQueueNotify: Failed to raise an interrupt (%Rrc).\n", INSTANCE(pVirtio), rc)); 123 } 124 } 125 126 bool virtioQueueInit(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName) 127 { 128 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 129 PVIRTQ_CONTEXT_T pVirtQ = &(pVirtio->queueContext[qIdx]); 130 if (pVirtio->uQueueEnable[qIdx]) 131 { 132 Log2Func(("Queue name: %-16s\n", pcszName)); 133 pVirtQ->uNextAvailIdx = 0; 134 pVirtQ->uNextUsedIdx = 0; 135 RTStrCopy((char *)pVirtQ->pcszName, sizeof(pVirtQ->pcszName), pcszName); 136 return true; 137 } 138 return false; 139 } 140 141 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx) 142 { 143 return (const char *)((PVIRTIOSTATE)hVirtio)->queueContext[qIdx].pcszName; 144 } 145 146 int virtioGetNumQueues(VIRTIOHANDLE hVirtio) 147 { 148 return ((PVIRTIOSTATE)(hVirtio))->uNumQueues; 149 } 150 151 bool virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx) 152 { 153 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 154 PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx]; 155 156 if (virtioQueueIsEmpty(pVirtio, qIdx)) 182 157 return false; 183 158 184 Log2(("%s virtQueueSkip: %s avail_idx=%u\n", INSTANCE(pState), 185 QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex)); 186 pQueue->uNextAvailIndex++; 187 */ 159 Log2Func(("%s: %s avail_idx=%u\n", INSTANCE(pVirtio), 160 pQueueContext->pcszName, pQueueContext->uNextAvailIdx)); 161 pQueueContext->uNextAvailIdx++; 188 162 return true; 189 163 } 190 164 191 bool virtQueueGet(PVIRTIOSTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove) 192 { 193 194 RT_NOREF4(pState, pQueue, pElem, fRemove); 195 196 /* PK TODO: Adapt to VirtIO 1.0 197 if (virtQueueIsEmpty(pState, pQueue)) 165 bool virtioQueueIsEmpty(VIRTIOHANDLE hVirtio, uint16_t qIdx) 166 { 167 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 168 return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->queueContext->uNextAvailIdx; 169 } 170 171 bool virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec) 172 { 173 return virtioQueueGet(hVirtio, qIdx, pBufVec, /* fRemove */ false); 174 } 175 176 bool virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, bool fRemove) 177 { 178 179 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 180 PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx]; 181 182 if (vqIsEmpty(pVirtio, qIdx)) 198 183 return false; 199 184 200 pElem->nIn = pElem->nOut = 0; 201 202 Log2(("%s virtQueueGet: %s avail_idx=%u\n", INSTANCE(pState), 203 QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex)); 185 pBufVec->cSegsIn = pBufVec->cSegsOut = 0; 186 187 Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pQueueContext->pcszName, pQueueContext->uNextAvailIdx)); 188 189 uint16_t uDescIdx; 190 pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pQueueContext->uNextAvailIdx); 191 192 if (fRemove) 193 pQueueContext->uNextAvailIdx++; 204 194 205 195 VIRTQ_DESC_T desc; 206 uint16_t idx = virtQueueReadAvail(pState, &pQueue->VirtQ, pQueue->uNextAvailIndex);207 if (fRemove)208 pQueue->uNextAvailIndex++;209 pElem->idx = idx;210 196 do 211 197 { 212 V QUEUESEG*pSeg;213 214 / /215 // Malicious guests may try to trick us into writing beyond aSegsIn or216 // aSegsOut boundaries by linking several descriptors into a loop. We217 // cannot possibly get a sequence of linked descriptors exceeding the218 // total number of descriptors in the ring (see @bugref{8620}).219 ///220 if (p Elem->nIn + pElem->nOut >= VIRTQ_MAX_SIZE)198 VIRTQ_SEG_T *pSeg; 199 200 /** 201 * Malicious or inept guests may go beyond aSegsIn or aSegsOut boundaries by linking 202 * several descriptors into a loop. Since there is no legitimate way to get a sequences of 203 * linked descriptors exceeding the total number of descriptors in the ring (see @bugref{8620}), 204 * the following aborts I/O if breech and employs a simple log throttling algorithm to notify. 205 */ 206 if (pBufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE) 221 207 { 222 208 static volatile uint32_t s_cMessages = 0; … … 224 210 if (ASMAtomicIncU32(&s_cMessages) == ASMAtomicReadU32(&s_cThreshold)) 225 211 { 226 LogRel(("%s: too many linked descriptors; check if the guest arranges descriptors in a loop.\n", 227 INSTANCE(pState))); 212 LogRel(("%s: too many linked descriptors; " 213 "check if the guest arranges descriptors in a loop.\n", 214 INSTANCE(pVirtio))); 228 215 if (ASMAtomicReadU32(&s_cMessages) != 1) 229 216 LogRel(("%s: (the above error has occured %u times so far)\n", 230 INSTANCE(p State), ASMAtomicReadU32(&s_cMessages)));217 INSTANCE(pVirtio), ASMAtomicReadU32(&s_cMessages))); 231 218 ASMAtomicWriteU32(&s_cThreshold, ASMAtomicReadU32(&s_cThreshold) * 10); 232 219 } … … 235 222 RT_UNTRUSTED_VALIDATED_FENCE(); 236 223 237 v irtQueueReadDesc(pState, &pQueue->VirtQ, idx, &desc);238 if (desc. u16Flags & VIRTQ_DESC_T_F_WRITE)239 { 240 Log2 (("%s virtQueueGet: %s IN seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),241 QUEUENAME(pState, pQueue), pElem->nIn, idx, desc.addr, desc.uLen));242 pSeg = & pElem->aSegsIn[pElem->nIn++];224 vqReadDesc(pVirtio, qIdx, uDescIdx, &desc); 225 if (desc.fFlags & VIRTQ_DESC_F_WRITE) 226 { 227 Log2Func(("%s: %s IN seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio), 228 pQueueContext->pcszName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb)); 229 pSeg = &(pBufVec->aSegsIn[pBufVec->cSegsIn++]); 243 230 } 244 231 else 245 232 { 246 Log2 (("%s virtQueueGet: %s OUT seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),247 QUEUENAME(pState, pQueue), pElem->nOut, idx, desc.addr, desc.uLen));248 pSeg = & pElem->aSegsOut[pElem->nOut++];249 } 250 251 pSeg->addr = desc.addr;252 pSeg->cb = desc. uLen;233 Log2Func(("%s: %s IN seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio), 234 pQueueContext->pcszName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb)); 235 pSeg = &(pBufVec->aSegsOut[pBufVec->cSegsOut++]); 236 } 237 238 pSeg->addr = (RTGCPHYS)desc.pGcPhysBuf; 239 pSeg->cb = desc.cb; 253 240 pSeg->pv = NULL; 254 241 255 idx = desc.next;256 } while (desc. u16Flags & VIRTQ_DESC_T_F_NEXT);257 258 Log2 (("%s virtQueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState),259 QUEUENAME(pState, pQueue), pElem->idx, pElem->nIn, pElem->nOut));260 */ 242 uDescIdx = desc.uDescIdxNext; 243 } while (desc.fFlags & VIRTQ_DESC_F_NEXT); 244 245 Log2Func(("%s: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pVirtio), 246 pQueueContext->pcszName, pBufVec->uDescIdx, pBufVec->cSegsIn, pBufVec->cSegsOut)); 247 261 248 return true; 262 249 } 263 250 264 265 266 void virtQueuePut(PVIRTIOSTATE pState, PVQUEUE pQueue, 267 PVQUEUEELEM pElem, uint32_t uTotalLen, uint32_t uReserved) 268 { 269 270 RT_NOREF5(pState, pQueue, pElem, uTotalLen, uReserved); 271 272 /* PK TODO Re-work this for VirtIO 1.0 273 Log2(("%s virtQueuePut: %s" 274 " desc_idx=%u acb=%u (%u)\n", 275 INSTANCE(pState), QUEUENAME(pState, pQueue), 276 pElem->idx, uTotalLen, uReserved)); 277 278 Assert(uReserved < uTotalLen); 279 280 uint32_t cbLen = uTotalLen - uReserved; 281 uint32_t cbSkip = uReserved; 282 283 for (unsigned i = 0; i < pElem->nIn && cbLen > 0; ++i) 284 { 285 if (cbSkip >= pElem->aSegsIn[i].cb) // segment completely skipped? 286 { 287 cbSkip -= pElem->aSegsIn[i].cb; 288 continue; 289 } 290 291 uint32_t cbSegLen = pElem->aSegsIn[i].cb - cbSkip; 292 if (cbSegLen > cbLen) // last segment only partially used? 293 cbSegLen = cbLen; 294 295 // 296 // XXX: We should assert pv != NULL, but we need to check and 297 // fix all callers first. 298 // 299 if (pElem->aSegsIn[i].pv != NULL) 300 { 301 Log2(("%s virtQueuePut: %s" 302 " used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", 303 INSTANCE(pState), QUEUENAME(pState, pQueue), 304 pQueue->uNextUsedIndex, i, 305 (void *)pElem->aSegsIn[i].addr, pElem->aSegsIn[i].pv, 306 pElem->aSegsIn[i].cb, cbSegLen)); 307 308 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 309 pElem->aSegsIn[i].addr + cbSkip, 310 pElem->aSegsIn[i].pv, 311 cbSegLen); 312 } 313 314 cbSkip = 0; 315 cbLen -= cbSegLen; 316 } 317 318 Log2(("%s virtQueuePut: %s" 319 " used_idx=%u guest_used_idx=%u id=%u len=%u\n", 320 INSTANCE(pState), QUEUENAME(pState, pQueue), 321 pQueue->uNextUsedIndex, virtQueueReadUsedIndex(pState, &pQueue->VirtQ), 322 pElem->idx, uTotalLen)); 323 324 virtQueueWriteUsedElem(pState, &pQueue->VirtQ, 325 pQueue->uNextUsedIndex++, 326 pElem->idx, uTotalLen); 327 */ 328 329 } 330 331 332 void virtQueueNotify(PVIRTIOSTATE pState, PVQUEUE pQueue) 333 { 334 335 RT_NOREF2(pState, pQueue); 336 /* PK TODO Adapt to VirtIO 1.0 337 LogFlow(("%s virtQueueNotify: %s availFlags=%x guestFeatures=%x virtQueue is %sempty\n", 338 INSTANCE(pState), QUEUENAME(pState, pQueue), 339 virtQueueReadAvailFlags(pState, &pQueue->VirtQ), 340 pState->uGuestFeatures, virtQueueIsEmpty(pState, pQueue)?"":"not ")); 341 if (!(virtQueueReadAvailFlags(pState, &pQueue->VirtQ) & VIRTQ_AVAIL_T_F_NO_INTERRUPT) 342 || ((pState->uGuestFeatures & VIRTIO_F_NOTIFY_ON_EMPTY) && virtQueueIsEmpty(pState, pQueue))) 343 { 344 int rc = virtioRaiseInterrupt(pState, VERR_INTERNAL_ERROR, VIRTIO_ISR_QUEUE); 345 if (RT_FAILURE(rc)) 346 Log(("%s virtQueueNotify: Failed to raise an interrupt (%Rrc).\n", INSTANCE(pState), rc)); 347 } 348 */ 349 } 350 351 void virtQueueSync(PVIRTIOSTATE pState, PVQUEUE pQueue) 352 { 353 RT_NOREF(pState, pQueue); 354 /* PK TODO Adapt to VirtIO 1.0 355 Log2(("%s virtQueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState), 356 QUEUENAME(pState, pQueue), virtQueueReadUsedIndex(pState, &pQueue->VirtQ), pQueue->uNextUsedIndex)); 357 virtQueueWriteUsedIndex(pState, &pQueue->VirtQ, pQueue->uNextUsedIndex); 358 virtQueueNotify(pState, pQueue); 359 */ 360 } 361 362 363 364 /** 365 * Raise interrupt. 366 * 367 * @param pState The device state structure. 368 * @param rcBusy Status code to return when the critical section is busy. 369 * @param u8IntCause Interrupt cause bit mask to set in PCI ISR port. 370 */ 371 __attribute__((unused)) 372 int virtioRaiseInterrupt(VIRTIOSTATE *pState, int rcBusy, uint8_t u8IntCause) 373 { 374 RT_NOREF2(pState, u8IntCause); 375 RT_NOREF_PV(rcBusy); 376 LogFlow(("%s virtioRaiseInterrupt: u8IntCause=%x\n", 377 INSTANCE(pState), u8IntCause)); 378 379 pState->uISR |= u8IntCause; 380 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 1); 381 return VINF_SUCCESS; 382 } 383 384 /** 385 * Lower interrupt. 386 * 387 * @param pState The device state structure. 388 */ 389 __attribute__((unused)) 390 static void virtioLowerInterrupt(VIRTIOSTATE *pState) 391 { 392 LogFlow(("%s virtioLowerInterrupt\n", INSTANCE(pState))); 393 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 0); 394 } 395 396 397 #ifdef IN_RING3 398 /** 399 * Saves the state of device. 400 * 401 * @returns VBox status code. 402 * @param pDevIns The device instance. 403 * @param pSSM The handle to the saved state. 404 */ 405 int virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM) 406 { 407 int rc = VINF_SUCCESS; 408 virtioDumpState(pVirtio, "virtioSaveExec"); 409 RT_NOREF(pSSM); 410 /* 411 * PK TODO save guest features, queue selector, sttus ISR, 412 * and per queue info (size, address, indicies)... 413 * using calls like SSMR3PutU8(), SSMR3PutU16(), SSMR3PutU16()... 414 * and AssertRCReturn(rc, rc) 415 */ 416 417 return rc; 418 } 419 420 /** 421 * Loads a saved device state. 422 * 423 * @returns VBox status code. 424 * @param pDevIns The device instance. 425 * @param pSSM The handle to the saved state. 426 * @param uVersion The data unit version number. 427 * @param uPass The data pass. 428 */ 429 int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t uNumQueues) 430 { 431 RT_NOREF5(pVirtio, pSSM, uVersion, uPass, uNumQueues); 432 int rc = VINF_SUCCESS; 433 virtioDumpState(pVirtio, "virtioLoadExec"); 434 435 /* 436 * PK TODO, restore everything saved in virtioSaveExect, using 437 * using calls like SSMR3PutU8(), SSMR3PutU16(), SSMR3PutU16()... 438 * and AssertRCReturn(rc, rc) 439 */ 440 if (uPass == SSM_PASS_FINAL) 441 { 442 } 443 return rc; 444 } 445 446 /** 251 void virtioQueuePut(VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, uint32_t cb) 252 { 253 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 254 PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx]; 255 256 Log2Func(("%s: %s desc_idx=%u acb=%u\n", 257 INSTANCE(pVirtio), pQueueContext->pcszName, pBufVec->uDescIdx, cb)); 258 259 uint32_t cbRemaining = cb; 260 261 for (uint32_t iSeg = 0; iSeg < pBufVec->cSegsIn && cbRemaining > 0; ++iSeg) 262 { 263 uint32_t cbSegLen = pBufVec->aSegsIn[iSeg].cb; 264 if (cbSegLen > cbRemaining) // last segment only partially used? 265 cbSegLen = cbRemaining; 266 267 Assert(pBufVec->aSegsIn[iSeg].pv != NULL); 268 269 if (pBufVec->aSegsIn[iSeg].pv != NULL) 270 { 271 Log2Func(("%s: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", 272 INSTANCE(pVirtio), pQueueContext->pcszName, 273 pQueueContext->uNextUsedIdx, iSeg, 274 (void *)pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, 275 pBufVec->aSegsIn[iSeg].cb, cbSegLen)); 276 277 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 278 pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, cbSegLen); 279 } 280 cbRemaining -= cbSegLen; 281 } 282 283 uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx); 284 Log2Func(("%s: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n", 285 INSTANCE(pVirtio), pQueueContext->pcszName, 286 pQueueContext->uNextUsedIdx, uDescIdx, pBufVec->uDescIdx, cb)); 287 288 vqWriteUsedElem(pVirtio, qIdx, pQueueContext->uNextUsedIdx, pBufVec->uDescIdx, cb); 289 } 290 291 void virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx) 292 { 293 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio; 294 PVIRTQ_CONTEXT_T pQueueContext = &pVirtio->queueContext[qIdx]; 295 296 uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx); 297 Log2Func(("%s: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pVirtio), pQueueContext->uNextUsedIdx, uDescIdx)); 298 vqWriteUsedRingDescIdx(pVirtio, qIdx, pQueueContext->uNextUsedIdx); 299 vqNotify(pVirtio, qIdx); 300 } 301 302 /** 303 * 304 * NOTE: The consumer (PDM device) must call this function to 'forward' a relocation call. 305 * 447 306 * Device relocation callback. 307 * 448 308 * 449 309 * When this callback is called the device instance data, and if the … … 464 324 RT_NOREF(offDelta); 465 325 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 466 326 LogFunc(("%s\n", INSTANCE(pVirtio))); 327 328 pVirtio->pDevInsR3 = pDevIns; 467 329 pVirtio->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 468 // TBD 469 } 470 471 PVQUEUE virtioAddQueue(VIRTIOSTATE* pState, unsigned cbQueue, const char *pcszName) 472 { 473 474 RT_NOREF3(pState, cbQueue, pcszName); 475 /* PK TODO Adapt to VirtIO 1.0 476 477 PVQUEUE pQueue = NULL; 478 // Find an empty queue slot 479 for (unsigned i = 0; i < pState->uNumQueues; i++) 480 { 481 if (pState->Queues[i].VirtQ.cbQueue == 0) 482 { 483 pQueue = &pState->Queues[i]; 484 break; 485 } 486 } 487 488 if (!pQueue) 489 { 490 Log(("%s Too many queues being added, no empty slots available!\n", INSTANCE(pState))); 491 } 492 else 493 { 494 pQueue->VirtQ.cbQueue = cbQueue; 495 pQueue->VirtQ.addrDescriptors = 0; 496 pQueue->uPageNumber = 0; 497 pQueue->pfnCallback = pfnCallback; 498 pQueue->pcszName = pcszName; 499 } 500 return pQueue; 501 */ 502 return NULL;// Temporary 503 } 504 505 506 330 pVirtio->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 331 } 332 333 /** 334 * Raise interrupt. 335 * 336 * @param pVirtio The device state structure. 337 * @param uCause Interrupt cause bit mask to set in PCI ISR port. 338 */ 339 static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause) 340 { 341 if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT) 342 LogFlowFunc(("%s: Cause: queue interrupt\n", INSTANCE(pVirtio))); 343 else 344 if (uCause == VIRTIO_ISR_DEVICE_CONFIG) 345 LogFlowFunc(("%s: Cause: device config\n", INSTANCE(pVirtio))); 346 347 pVirtio->uISR |= uCause; 348 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 1); 349 return VINF_SUCCESS; 350 } 351 352 /** 353 * Lower interrupt. 354 * 355 * @param pVirtio The device state structure. 356 */ 507 357 __attribute__((unused)) 508 static void virtQueueInit(PVQUEUE pQueue, uint32_t uPageNumber) 509 { 510 RT_NOREF2(pQueue, uPageNumber); 511 512 /* PK TODO, re-work this for VirtIO 1.0 513 pQueue->VirtQ.addrDescriptors = (uint64_t)uPageNumber << PAGE_SHIFT; 514 515 pQueue->VirtQ.addrAvail = pQueue->VirtQ.addrDescriptors 516 + sizeof(VIRTQ_DESC_T) * pQueue->VirtQ.cbQueue; 517 518 pQueue->VirtQ.addrUsed = RT_ALIGN(pQueue->VirtQ.addrAvail 519 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, ring[pQueue->VirtQ.cbQueue]) 520 + sizeof(uint16_t), // virtio 1.0 adds a 16-bit field following ring data 521 PAGE_SIZE); // The used ring must start from the next page. 522 523 pQueue->uNextAvailIndex = 0; 524 pQueue->uNextUsedIndex = 0; 525 */ 526 527 } 528 529 530 __attribute__((unused)) 531 static void virtQueueReset(PVQUEUE pQueue) 532 { 533 RT_NOREF(pQueue); 534 /* PK TODO Adapt to VirtIO 1.0 535 pQueue->VirtQ.addrDescriptors = 0; 536 pQueue->VirtQ.addrAvail = 0; 537 pQueue->VirtQ.addrUsed = 0; 538 pQueue->uNextAvailIndex = 0; 539 pQueue->uNextUsedIndex = 0; 540 pQueue->uPageNumber = 0; 541 */ 358 static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio) 359 { 360 LogFlowFunc(("%s\n", INSTANCE(pVirtio))); 361 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0); 542 362 } 543 363 … … 548 368 * @param fConfigChange - True if cfg change notification else, queue notification 549 369 */ 550 static void virtioNotifyDriver(VIRTIOHANDLE hVirtio, bool fConfigChange) 551 { 552 RT_NOREF(hVirtio); 553 LogFunc(("fConfigChange = %d\n", fConfigChange)); 554 } 555 556 557 int virtioReset(VIRTIOHANDLE hVirtio) /* Part of our "custom API" */ 558 { 559 PVIRTIOSTATE pVirtio = H2P(hVirtio); 560 561 RT_NOREF(pVirtio); 562 /* PK TODO Adapt to VirtIO 1.09 563 pState->uGuestFeatures = 0; 564 pState->uQueueSelector = 0; 565 pState->uStatus = 0; 566 pState->uISR = 0; 567 568 for (unsigned i = 0; i < pState->uNumQueues; i++) 569 virtQueueReset(&pState->Queues[i]); 570 virtioNotify(pVirtio); 571 */ 572 return VINF_SUCCESS; 370 __attribute__((unused)) 371 static void virtioNotifyDriver(PVIRTIOSTATE pVirtio, uint8_t uCause) 372 { 373 /** 374 * add criteria 375 */ 376 RT_NOREF(pVirtio); 377 if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT) 378 Log2Func(("%s: Cause: queue interrupt\n", INSTANCE(pVirtio))); 379 else 380 if (uCause == VIRTIO_ISR_DEVICE_CONFIG) 381 Log2Func(("%s: Cause: device config\n", INSTANCE(pVirtio))); 573 382 } 574 383 … … 580 389 { 581 390 pVirtio->fGenUpdatePending = true; 582 virtioNotifyDriver(pVirtio, true); 583 } 584 } 391 virtioNotifyDriver(pVirtio, VIRTIO_ISR_DEVICE_CONFIG); 392 } 393 } 394 395 static void vqReset(PVIRTIOSTATE pVirtio, uint16_t qIdx) 396 { 397 PVIRTQ_CONTEXT_T pVirtQ = &pVirtio->queueContext[qIdx]; 398 pVirtQ->uNextAvailIdx = 0; 399 pVirtQ->uNextUsedIdx = 0; 400 pVirtio->uQueueSize[qIdx] = VIRTQ_MAX_SIZE; 401 pVirtio->uQueueNotifyOff[qIdx] = qIdx; 402 } 403 585 404 586 405 static void virtioResetDevice(PVIRTIOSTATE pVirtio) 587 406 { 588 589 LogFunc(("\n")); 590 pVirtio->uDeviceStatus = 0; 407 Log2Func(("\n")); 591 408 pVirtio->uDeviceFeaturesSelect = 0; 592 409 pVirtio->uDriverFeaturesSelect = 0; 593 410 pVirtio->uConfigGeneration = 0; 594 pVirtio->uNumQueues = VIRTIO_MAX_QUEUES; 595 596 for (uint32_t i = 0; i < pVirtio->uNumQueues; i++) 597 { 598 pVirtio->uQueueSize[i] = VIRTQ_MAX_SIZE; 599 pVirtio->uQueueNotifyOff[i] = i; 600 // virtqNotify(); 601 } 411 pVirtio->uDeviceStatus = 0; 412 pVirtio->uISR = 0; 413 414 #ifndef MSIX_SUPPORT 415 /** This is required by VirtIO 1.0 specification, section 4.1.5.1.2 */ 416 pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR; 417 for (int i = 0; i < VIRTQ_MAX_CNT; i++) 418 pVirtio->uQueueMsixVector[i] = VIRTIO_MSI_NO_VECTOR; 419 #endif 420 421 #if DISABLE_GUEST_DRIVER /** Temporary debugging aid */ 422 pVirtio->uNumQueues = 0; 423 #else 424 pVirtio->uNumQueues = VIRTQ_MAX_CNT; 425 #endif 426 for (uint16_t qIdx = 0; qIdx < pVirtio->uNumQueues; qIdx++) 427 vqReset(pVirtio, qIdx); 602 428 } 603 429 … … 616 442 int rc = VINF_SUCCESS; 617 443 uint64_t val; 618 if ( COMMON_CFG(uDeviceFeatures))444 if (MATCH_COMMON_CFG(uDeviceFeatures)) 619 445 { 620 446 if (fWrite) /* Guest WRITE pCommonCfg>uDeviceFeatures */ … … 622 448 else /* Guest READ pCommonCfg->uDeviceFeatures */ 623 449 { 624 uint32_t uIntraOff = uOffset - RT_ OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures);450 uint32_t uIntraOff = uOffset - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDeviceFeatures); 625 451 switch(pVirtio->uDeviceFeaturesSelect) 626 452 { … … 628 454 val = pVirtio->uDeviceFeatures & 0xffffffff; 629 455 memcpy((void *)pv, (const void *)&val, cb); 630 LOG_ ACCESSOR(uDeviceFeatures);456 LOG_COMMON_CFG_ACCESS(uDeviceFeatures); 631 457 break; 632 458 case 1: … … 634 460 uIntraOff += 4; 635 461 memcpy((void *)pv, (const void *)&val, cb); 636 LOG_ ACCESSOR(uDeviceFeatures);462 LOG_COMMON_CFG_ACCESS(uDeviceFeatures); 637 463 break; 638 464 default: 639 Log Func(("Guest read uDeviceFeatures with out of range selector (%d), returning 0\n",465 Log2Func(("Guest read uDeviceFeatures with out of range selector (%d), returning 0\n", 640 466 pVirtio->uDeviceFeaturesSelect)); 641 467 return VERR_ACCESS_DENIED; … … 643 469 } 644 470 } 645 else if ( COMMON_CFG(uDriverFeatures))471 else if (MATCH_COMMON_CFG(uDriverFeatures)) 646 472 { 647 473 if (fWrite) /* Guest WRITE pCommonCfg->udriverFeatures */ 648 474 { 649 uint32_t uIntraOff = uOffset - RT_ OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);475 uint32_t uIntraOff = uOffset - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures); 650 476 switch(pVirtio->uDriverFeaturesSelect) 651 477 { 652 478 case 0: 653 479 memcpy(&pVirtio->uDriverFeatures, pv, cb); 654 LOG_ ACCESSOR(uDriverFeatures);480 LOG_COMMON_CFG_ACCESS(uDriverFeatures); 655 481 break; 656 482 case 1: 657 483 memcpy(((char *)&pVirtio->uDriverFeatures) + sizeof(uint32_t), pv, cb); 658 484 uIntraOff += 4; 659 LOG_ ACCESSOR(uDriverFeatures);485 LOG_COMMON_CFG_ACCESS(uDriverFeatures); 660 486 break; 661 487 default: 662 Log Func(("Guest wrote uDriverFeatures with out of range selector (%d), returning 0\n",488 Log2Func(("Guest wrote uDriverFeatures with out of range selector (%d), returning 0\n", 663 489 pVirtio->uDriverFeaturesSelect)); 664 490 return VERR_ACCESS_DENIED; … … 667 493 else /* Guest READ pCommonCfg->udriverFeatures */ 668 494 { 669 uint32_t uIntraOff = uOffset - RT_ OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures);495 uint32_t uIntraOff = uOffset - RT_UOFFSETOF(VIRTIO_PCI_COMMON_CFG_T, uDriverFeatures); 670 496 switch(pVirtio->uDriverFeaturesSelect) 671 497 { … … 673 499 val = pVirtio->uDriverFeatures & 0xffffffff; 674 500 memcpy((void *)pv, (const void *)&val, cb); 675 LOG_ ACCESSOR(uDriverFeatures);501 LOG_COMMON_CFG_ACCESS(uDriverFeatures); 676 502 break; 677 503 case 1: … … 679 505 uIntraOff += 4; 680 506 memcpy((void *)pv, (const void *)&val, cb); 681 LOG_ ACCESSOR(uDriverFeatures);507 LOG_COMMON_CFG_ACCESS(uDriverFeatures); 682 508 break; 683 509 default: 684 Log Func(("Guest read uDriverFeatures with out of range selector (%d), returning 0\n",510 Log2Func(("Guest read uDriverFeatures with out of range selector (%d), returning 0\n", 685 511 pVirtio->uDriverFeaturesSelect)); 686 512 return VERR_ACCESS_DENIED; … … 688 514 } 689 515 } 690 else if ( COMMON_CFG(uNumQueues))516 else if (MATCH_COMMON_CFG(uNumQueues)) 691 517 { 692 518 if (fWrite) 693 519 { 694 Log Func(("Guest attempted to write readonly virtio_pci_common_cfg.num_queues\n"));520 Log2Func(("Guest attempted to write readonly virtio_pci_common_cfg.num_queues\n")); 695 521 return VERR_ACCESS_DENIED; 696 522 } … … 698 524 { 699 525 uint32_t uIntraOff = 0; 700 *(uint16_t *)pv = VIRT IO_MAX_QUEUES;701 LOG_ ACCESSOR(uNumQueues);702 } 703 } 704 else if ( COMMON_CFG(uDeviceStatus))526 *(uint16_t *)pv = VIRTQ_MAX_CNT; 527 LOG_COMMON_CFG_ACCESS(uNumQueues); 528 } 529 } 530 else if (MATCH_COMMON_CFG(uDeviceStatus)) 705 531 { 706 532 if (fWrite) /* Guest WRITE pCommonCfg->uDeviceStatus */ 707 533 { 708 534 pVirtio->uDeviceStatus = *(uint8_t *)pv; 709 Log Func(("Guest wrote uDeviceStatus ................ ("));535 Log2Func(("Guest wrote uDeviceStatus ................ (")); 710 536 virtioLogDeviceStatus(pVirtio->uDeviceStatus); 711 537 Log((")\n")); 712 538 if (pVirtio->uDeviceStatus == 0) 713 539 virtioResetDevice(pVirtio); 540 pVirtio->virtioCallbacks.pfnVirtioStatusChanged( 541 (VIRTIOHANDLE)pVirtio, pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK); 714 542 } 715 543 else /* Guest READ pCommonCfg->uDeviceStatus */ 716 544 { 717 Log Func(("Guest read uDeviceStatus ................ ("));545 Log2Func(("Guest read uDeviceStatus ................ (")); 718 546 *(uint32_t *)pv = pVirtio->uDeviceStatus; 719 547 virtioLogDeviceStatus(pVirtio->uDeviceStatus); … … 721 549 } 722 550 } 723 else if ( COMMON_CFG(uMsixConfig))724 { 725 ACCESSOR(uMsixConfig);726 } 727 else if ( COMMON_CFG(uDeviceFeaturesSelect))728 { 729 ACCESSOR(uDeviceFeaturesSelect);730 } 731 else if ( COMMON_CFG(uDriverFeaturesSelect))732 { 733 ACCESSOR(uDriverFeaturesSelect);734 } 735 else if ( COMMON_CFG(uConfigGeneration))736 { 737 ACCESSOR_READONLY(uConfigGeneration);738 } 739 else if ( COMMON_CFG(uQueueSelect))740 { 741 ACCESSOR(uQueueSelect);742 } 743 else if ( COMMON_CFG(uQueueSize))744 { 745 ACCESSOR_WITH_IDX(uQueueSize, pVirtio->uQueueSelect);746 } 747 else if ( COMMON_CFG(uQueueMsixVector))748 { 749 ACCESSOR_WITH_IDX(uQueueMsixVector, pVirtio->uQueueSelect);750 } 751 else if ( COMMON_CFG(uQueueEnable))752 { 753 ACCESSOR_WITH_IDX(uQueueEnable, pVirtio->uQueueSelect);754 } 755 else if ( COMMON_CFG(uQueueNotifyOff))756 { 757 ACCESSOR_READONLY_WITH_IDX(uQueueNotifyOff, pVirtio->uQueueSelect);758 } 759 else if ( COMMON_CFG(uQueueDesc))760 { 761 ACCESSOR_WITH_IDX(uQueueDesc, pVirtio->uQueueSelect);762 } 763 else if ( COMMON_CFG(uQueueAvail))764 { 765 ACCESSOR_WITH_IDX(uQueueAvail, pVirtio->uQueueSelect);766 } 767 else if ( COMMON_CFG(uQueueUsed))768 { 769 ACCESSOR_WITH_IDX(uQueueUsed, pVirtio->uQueueSelect);551 else if (MATCH_COMMON_CFG(uMsixConfig)) 552 { 553 COMMON_CFG_ACCESSOR(uMsixConfig); 554 } 555 else if (MATCH_COMMON_CFG(uDeviceFeaturesSelect)) 556 { 557 COMMON_CFG_ACCESSOR(uDeviceFeaturesSelect); 558 } 559 else if (MATCH_COMMON_CFG(uDriverFeaturesSelect)) 560 { 561 COMMON_CFG_ACCESSOR(uDriverFeaturesSelect); 562 } 563 else if (MATCH_COMMON_CFG(uConfigGeneration)) 564 { 565 COMMON_CFG_ACCESSOR_READONLY(uConfigGeneration); 566 } 567 else if (MATCH_COMMON_CFG(uQueueSelect)) 568 { 569 COMMON_CFG_ACCESSOR(uQueueSelect); 570 } 571 else if (MATCH_COMMON_CFG(uQueueSize)) 572 { 573 COMMON_CFG_ACCESSOR_INDEXED(uQueueSize, pVirtio->uQueueSelect); 574 } 575 else if (MATCH_COMMON_CFG(uQueueMsixVector)) 576 { 577 COMMON_CFG_ACCESSOR_INDEXED(uQueueMsixVector, pVirtio->uQueueSelect); 578 } 579 else if (MATCH_COMMON_CFG(uQueueEnable)) 580 { 581 COMMON_CFG_ACCESSOR_INDEXED(uQueueEnable, pVirtio->uQueueSelect); 582 } 583 else if (MATCH_COMMON_CFG(uQueueNotifyOff)) 584 { 585 COMMON_CFG_ACCESSOR_INDEXED_READONLY(uQueueNotifyOff, pVirtio->uQueueSelect); 586 } 587 else if (MATCH_COMMON_CFG(pGcPhysQueueDesc)) 588 { 589 COMMON_CFG_ACCESSOR_INDEXED(pGcPhysQueueDesc, pVirtio->uQueueSelect); 590 } 591 else if (MATCH_COMMON_CFG(pGcPhysQueueAvail)) 592 { 593 COMMON_CFG_ACCESSOR_INDEXED(pGcPhysQueueAvail, pVirtio->uQueueSelect); 594 } 595 else if (MATCH_COMMON_CFG(pGcPhysQueueUsed)) 596 { 597 COMMON_CFG_ACCESSOR_INDEXED(pGcPhysQueueUsed, pVirtio->uQueueSelect); 770 598 } 771 599 else 772 600 { 773 Log Func(("Bad guest %s access to virtio_pci_common_cfg: uOffset=%d, cb=%d\n",601 Log2Func(("Bad guest %s access to virtio_pci_common_cfg: uOffset=%d, cb=%d\n", 774 602 fWrite ? "write" : "read ", uOffset, cb)); 775 603 rc = VERR_ACCESS_DENIED; … … 794 622 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 795 623 int rc = VINF_SUCCESS; 796 797 //#ifdef LOG_ENABLED798 // LogFunc(("pVirtio=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pVirtio, GCPhysAddr, pv, cb, pv, cb));799 //#endif800 624 801 625 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap, fDevSpecific); … … 824 648 { 825 649 if (fDevSpecificFieldChanged) 826 Log Func(("Dev specific config field changed since last read, gen++ = %d\n",650 Log2Func(("Dev specific config field changed since last read, gen++ = %d\n", 827 651 pVirtio->uConfigGeneration)); 828 652 else 829 Log Func(("Config generation pending flag set, gen++ = %d\n",653 Log2Func(("Config generation pending flag set, gen++ = %d\n", 830 654 pVirtio->uConfigGeneration)); 831 655 ++pVirtio->uConfigGeneration; … … 842 666 if (fIsrCap) 843 667 { 844 *(uint8_t *)pv = pVirtio->fQueueInterrupt | pVirtio->fDeviceConfigInterrupt << 1; 845 LogFunc(("Read 0x%s from pIsrCap\n", *(uint8_t *)pv)); 668 *(uint8_t *)pv = pVirtio->uISR; 669 Log2Func(("Read 0x%02x from uISR (virtq interrupt: %d, dev config interrupt: %d)\n", 670 pVirtio->uISR & 0xff, 671 pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT, 672 !!(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG))); 673 pVirtio->uISR = 0; /** VirtIO specification requires reads of ISR to clear it */ 846 674 } 847 675 else { 848 676 849 AssertMsgFailed(("virtio: Read outside of capabilities region: GCPhysAddr=%RGp cb=%RGp\n", GCPhysAddr, cb)); 677 Log2Func(("Bad read access to mapped capabilities region:\n" 678 " pVirtio=%#p GCPhysAddr=%RGp cb=%u\n", 679 pVirtio, GCPhysAddr, pv, cb, pv, cb)); 850 680 } 851 681 return rc; 852 682 } 853 854 683 /** 855 684 * Memory mapped I/O Handler for PCI Capabilities write operations. … … 869 698 int rc = VINF_SUCCESS; 870 699 871 //#ifdef LOG_ENABLED872 // LogFunc(("pVirtio=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", pVirtio, GCPhysAddr, pv, cb, pv, cb));873 //#endif874 875 700 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysDeviceCap, pVirtio->pDeviceCap, fDevSpecific); 876 701 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysCommonCfg, pVirtio->pCommonCfgCap, fCommonCfg); 877 702 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysIsrCap, pVirtio->pIsrCap, fIsrCap); 703 MATCH_VIRTIO_CAP_STRUCT(pVirtio->pGcPhysNotifyCap, pVirtio->pNotifyCap, fNotifyCap); 878 704 879 705 if (fDevSpecific) … … 891 717 if (fIsrCap) 892 718 { 893 pVirtio->fQueueInterrupt = (*(uint8_t *)pv) & 1; 894 pVirtio->fDeviceConfigInterrupt = !!(*((uint8_t *)pv) & 2); 895 Log(("pIsrCap... setting fQueueInterrupt=%d fDeviceConfigInterrupt=%d\n", 896 pVirtio->fQueueInterrupt, pVirtio->fDeviceConfigInterrupt)); 719 pVirtio->uISR = *(uint8_t *)pv; 720 Log2Func(("Setting uISR = 0x%02x (virtq interrupt: %d, dev confg innterrupt: %d)\n", 721 pVirtio->uISR & 0xff, 722 pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT, 723 !!(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG))); 897 724 } 898 725 else 899 { 900 LogFunc(("virtio: Write outside of capabilities region:\nGCPhysAddr=%RGp cb=%RGp,", GCPhysAddr, cb)); 726 if (fNotifyCap && cb == 2) 727 { 728 uint32_t uNotifyBaseOffset = GCPhysAddr - pVirtio->pGcPhysNotifyCap; 729 uint16_t qIdx = uNotifyBaseOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER; 730 uint16_t uNotifiedIdx = *(uint16_t *)pv; 731 vqNotified(pVirtio, qIdx, uNotifiedIdx); 732 } 733 else 734 { 735 Log2Func(("Bad write access to mapped capabilities region:\n" 736 " pVirtio=%#p GCPhysAddr=%RGp pv=%#p{%.*Rhxs} cb=%u\n", 737 pVirtio, GCPhysAddr, pv, cb, pv, cb)); 901 738 } 902 739 return rc; 903 740 } 904 905 741 906 742 /** … … 926 762 if (RT_FAILURE(rc)) 927 763 { 928 Log Func(("virtio: PCI Capabilities failed to map GCPhysAddr=%RGp cb=%RGp, region=%d\n",764 Log2Func(("virtio: PCI Capabilities failed to map GCPhysAddr=%RGp cb=%RGp, region=%d\n", 929 765 GCPhysAddress, cb, iRegion)); 930 766 return rc; 931 767 } 932 Log Func(("virtio: PCI Capabilities mapped at GCPhysAddr=%RGp cb=%RGp, region=%d\n",768 Log2Func(("virtio: PCI Capabilities mapped at GCPhysAddr=%RGp cb=%RGp, region=%d\n", 933 769 GCPhysAddress, cb, iRegion)); 934 pVirtio-> GCPhysPciCapBase = GCPhysAddress;935 pVirtio->pGcPhysCommonCfg = GCPhysAddress + pVirtio->pCommonCfgCap->uOffset;936 pVirtio->pGcPhysNotifyCap = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset;937 pVirtio->pGcPhysIsrCap = GCPhysAddress + pVirtio->pIsrCap->uOffset;770 pVirtio->pGcPhysPciCapBase = GCPhysAddress; 771 pVirtio->pGcPhysCommonCfg = GCPhysAddress + pVirtio->pCommonCfgCap->uOffset; 772 pVirtio->pGcPhysNotifyCap = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset; 773 pVirtio->pGcPhysIsrCap = GCPhysAddress + pVirtio->pIsrCap->uOffset; 938 774 if (pVirtio->pDevSpecificCap) 939 775 pVirtio->pGcPhysDeviceCap = GCPhysAddress + pVirtio->pDeviceCap->uOffset; … … 958 794 uint32_t uAddress, unsigned cb) 959 795 { 960 // PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);961 796 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 962 797 … … 971 806 uint32_t pv = 0; 972 807 if (uBar == pVirtio->uVirtioCapBar) 973 (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio-> GCPhysPciCapBase + uOffset),808 (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset), 974 809 &pv, uLength); 975 810 else 976 811 { 977 Log Func(("Guest read virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring"));812 Log2Func(("Guest read virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring")); 978 813 return 0; 979 814 } 980 Log Func(("virtio: Guest read virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%d, length=%d, result=%d\n",815 Log2Func(("virtio: Guest read virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%d, length=%d, result=%d\n", 981 816 uBar, uOffset, uLength, pv)); 982 817 return pv; … … 1015 850 uint8_t uBar = pVirtio->pPciCfgCap->pciCap.uBar; 1016 851 if (uBar == pVirtio->uVirtioCapBar) 1017 (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio-> GCPhysPciCapBase + uOffset),852 (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->pGcPhysPciCapBase + uOffset), 1018 853 (void *)&u32Value, uLength); 1019 854 else 1020 855 { 1021 Log Func(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring"));856 Log2Func(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data using unconfigured BAR. Ignoring")); 1022 857 return VINF_SUCCESS; 1023 858 } 1024 Log Func(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%x, length=%x, value=%d\n",859 Log2Func(("Guest wrote virtio_pci_cfg_cap.pci_cfg_data, bar=%d, offset=%x, length=%x, value=%d\n", 1025 860 uBar, uOffset, uLength, u32Value)); 1026 861 return VINF_SUCCESS; … … 1030 865 1031 866 /** 1032 * @interface_method_impl{PDMIBASE,pfnQueryInterface}1033 */1034 void *virtioQueryInterface(PPDMIBASE pInterface, const char *pszIID)1035 {1036 VIRTIOSTATE *pThis = IFACE_TO_STATE(pInterface, IBase);1037 Assert(&pThis->IBase == pInterface);1038 1039 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);1040 return NULL;1041 }1042 1043 /**1044 867 * Get VirtIO accepted host-side features 1045 868 * … … 1047 870 * 1048 871 * @param pState Virtio state 1049 * @param uSelect Selects which 32-bit set of feature information to return 1050 */ 1051 1052 __attribute__((unused)) 1053 static uint64_t virtioGetHostFeatures(PVIRTIOSTATE pVirtio) 872 */ 873 uint64_t virtioGetAcceptedFeatures(PVIRTIOSTATE pVirtio) 1054 874 { 1055 875 return pVirtio->uDriverFeatures; 1056 }1057 1058 /**1059 *1060 * Set VirtIO available host-side features1061 *1062 * @returns VBox status code1063 *1064 * @param pState Virtio state1065 * @param uDeviceFeatures Feature bits (0-63) to set1066 */1067 1068 1069 void virtioSetHostFeatures(VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures)1070 {1071 H2P(hVirtio)->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures;1072 876 } 1073 877 … … 1080 884 * @param pState The device state structure. 1081 885 */ 1082 int virtioDestruct(VIRTIOSTATE* pState) 1083 { 1084 Log(("%s Destroying PCI instance\n", INSTANCE(pState))); 886 int virtioDestruct(PVIRTIOSTATE pVirtio) 887 { 888 RT_NOREF(pVirtio); 889 Log(("%s Destroying PCI instance\n", INSTANCE(pVirtio))); 1085 890 return VINF_SUCCESS; 1086 891 } 1087 892 1088 /** PK (temp note to self):1089 *1090 * Device needs to negotiate capabilities,1091 * then get queue size address information from driver.1092 *1093 * Still need consumer to pass in:1094 *1095 * num_queues1096 * config_generation1097 * Needs to manage feature negotiation1098 * That means consumer needs to pass in device-specific feature bits/values1099 * Device has to provie at least one notifier capability1100 *1101 * ISR config value are set by the device (config interrupt vs. queue interrupt)1102 *1103 */1104 1105 893 /** 1106 894 * Setup PCI device controller and Virtio state 1107 895 * 1108 * @param pDevIns Device instance data 1109 * @param pVirtio Device State 1110 * @param iInstance Instance number 1111 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure 1112 * @param pcszNameFmt Device instance name (format-specifier) 896 * @param pDevIns Device instance data 897 * @param pVirtio Device State 898 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure 899 * @param pcszInstance Device instance name (format-specifier) 1113 900 * @param uNumQueues Number of Virtio Queues created by consumer (driver) 1114 * @param uVirtioRegion Region number to map for PCi Capabilities structs 1115 * @param devCapReadCallback Client function to call back to handle device specific capabilities 1116 * @param devCapWriteCallback Client function to call back to handle device specific capabilities 1117 * @param cbDevSpecificCap Size of device specific struct 1118 * @param uNotifyOffMultiplier See VirtIO 1.0 spec 4.1.4.4 re: virtio_pci_notify_cap 1119 */ 1120 1121 int virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOHANDLE phVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams, 1122 const char *pcszNameFmt, uint32_t uNumQueues, uint32_t uVirtioCapBar, uint64_t uDeviceFeatures, 1123 PFNVIRTIODEVCAPREAD devCapReadCallback, PFNVIRTIODEVCAPWRITE devCapWriteCallback, 1124 uint16_t cbDevSpecificCap, void *pDevSpecificCap, uint32_t uNotifyOffMultiplier) 901 * @param uVirtioCapBar Region number to map for PCi Capabilities structs 902 * @param uDevSpecificFeatures VirtIO device-specific features offered by client 903 * @param devCapReadCallback Client handler to call upon guest read to device specific capabilities. 904 * @param devCapWriteCallback Client handler to call upon guest write to device specific capabilities. 905 * @param devStatusChangedCallback Client handler to call for major device status changes 906 * @param queueNotifiedCallback Client handler for guest-to-host notifications that avail queue has ring data 907 * @param ssmLiveExecCallback Client handler for SSM live exec 908 * @param ssmSaveExecCallback Client handler for SSM save exec 909 * @param ssmLoadExecCallback Client handler for SSM load exec 910 * @param ssmLoadDoneCallback Client handler for SSM load done 911 * @param cbDevSpecificCap Size of virtio_pci_device_cap device-specific struct 912 */ 913 int virtioConstruct(PPDMDEVINS pDevIns, 914 VIRTIOHANDLE *phVirtio, 915 PVIRTIOPCIPARAMS pPciParams, 916 const char *pcszInstance, 917 uint32_t uNumQueues, 918 uint32_t uVirtioCapBar, 919 uint64_t uDevSpecificFeatures, 920 PFNVIRTIODEVCAPREAD devCapReadCallback, 921 PFNVIRTIODEVCAPWRITE devCapWriteCallback, 922 PFNVIRTIOSTATUSCHANGED devStatusChangedCallback, 923 PFNVIRTIOQUEUENOTIFIED queueNotifiedCallback, 924 PFNSSMDEVLIVEEXEC ssmLiveExecCallback, 925 PFNSSMDEVSAVEEXEC ssmSaveExecCallback, 926 PFNSSMDEVLOADEXEC ssmLoadExecCallback, 927 PFNSSMDEVLOADDONE ssmLoadDoneCallback, 928 uint16_t cbDevSpecificCap, 929 void *pDevSpecificCap) 1125 930 { 1126 931 … … 1134 939 } 1135 940 1136 1137 941 pVirtio->uNumQueues = uNumQueues; 1138 pVirtio->uNotifyOffMultiplier = uNotifyOffMultiplier; 1139 pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures; 1140 1141 /* Init handles and log related stuff. */ 1142 RTStrPrintf(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszNameFmt, iInstance); 942 943 /** 944 * The host features offered include both device-specific features 945 * and reserved feature bits (device independent) 946 */ 947 pVirtio->uDeviceFeatures = uDevSpecificFeatures 948 | VIRTIO_F_VERSION_1 949 | VIRTIO_F_RING_EVENT_IDX 950 | VIRTIO_F_RING_INDIRECT_DESC; 951 952 RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance); 1143 953 1144 954 pVirtio->pDevInsR3 = pDevIns; … … 1147 957 pVirtio->uDeviceStatus = 0; 1148 958 pVirtio->cbDevSpecificCap = cbDevSpecificCap; 1149 pVirtio->pDevSpecificCap = pDevSpecificCap; 1150 /** 1151 * Need to keep a history of this relatively small virtio device-specific 1152 * configuration buffer, which is opaque to this encapsulation of the generic 1153 * part virtio operations, to track config changes to fields, in order to 1154 * update the configuration generation each change. (See VirtIO 1.0 section 4.1.4.3.1) 1155 */ 959 pVirtio->pDevSpecificCap = pDevSpecificCap; 960 1156 961 pVirtio->pPrevDevSpecificCap = RTMemAlloc(cbDevSpecificCap); 1157 962 if (!pVirtio->pPrevDevSpecificCap) … … 1161 966 return VERR_NO_MEMORY; 1162 967 } 968 1163 969 memcpy(pVirtio->pPrevDevSpecificCap, pVirtio->pDevSpecificCap, cbDevSpecificCap); 1164 970 pVirtio->uVirtioCapBar = uVirtioCapBar; 1165 pVirtio->virtioCallbacks.pfnVirtioDevCapRead = devCapReadCallback; 1166 pVirtio->virtioCallbacks.pfnVirtioDevCapWrite = devCapWriteCallback; 971 pVirtio->virtioCallbacks.pfnVirtioDevCapRead = devCapReadCallback; 972 pVirtio->virtioCallbacks.pfnVirtioDevCapWrite = devCapWriteCallback; 973 pVirtio->virtioCallbacks.pfnVirtioStatusChanged = devStatusChangedCallback; 974 pVirtio->virtioCallbacks.pfnVirtioQueueNotified = queueNotifiedCallback; 975 pVirtio->virtioCallbacks.pfnSSMDevLiveExec = ssmLiveExecCallback; 976 pVirtio->virtioCallbacks.pfnSSMDevSaveExec = ssmSaveExecCallback; 977 pVirtio->virtioCallbacks.pfnSSMDevLoadExec = ssmLoadExecCallback; 978 pVirtio->virtioCallbacks.pfnSSMDevLoadDone = ssmLoadDoneCallback; 979 1167 980 1168 981 /* Set PCI config registers (assume 32-bit mode) */ … … 1187 1000 } 1188 1001 1189 pVirtio->IBase = pDevIns->IBase; 1002 rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIO_SAVEDSTATE_VERSION, sizeof(*pVirtio), NULL, 1003 NULL, virtioR3LiveExec, NULL, NULL, virtioR3SaveExec, NULL, 1004 NULL, virtioR3LoadExec, virtioR3LoadDone); 1005 if (RT_FAILURE(rc)) 1006 { 1007 RTMemFree(pVirtio); 1008 return PDMDEV_SET_ERROR(pDevIns, rc, 1009 N_("virtio: cannot register SSM callbacks")); 1010 } 1190 1011 1191 1012 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pVirtio->dev, 1192 1013 virtioPciConfigRead, &pVirtio->pfnPciConfigReadOld, 1193 1014 virtioPciConfigWrite, &pVirtio->pfnPciConfigWriteOld); 1015 1194 1016 1195 1017 /** Construct & map PCI vendor-specific capabilities for virtio host negotiation with guest driver */ … … 1201 1023 #endif 1202 1024 1203 /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T)1025 /** The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T) 1204 1026 * as a mandatory but suboptimal alternative interface to host device capabilities, facilitating 1205 1027 * access the memory of any BAR. If the guest uses it (the VirtIO driver on Linux doesn't), … … 1219 1041 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1220 1042 pCfg->uBar = uVirtioCapBar; 1221 pCfg->uOffset = 0;1043 pCfg->uOffset = RT_ALIGN_32(0, 4); /* reminder, in case someone changes offset */ 1222 1044 pCfg->uLength = sizeof(VIRTIO_PCI_COMMON_CFG_T); 1223 1045 cbRegion += pCfg->uLength; 1224 1046 pVirtio->pCommonCfgCap = pCfg; 1225 1047 1226 /* Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based on assumption1048 /** Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based on assumption 1227 1049 * that each queue's uQueueNotifyOff is set equal to uQueueSelect's ordinal 1228 1050 * value of the queue */ … … 1234 1056 pCfg->uBar = uVirtioCapBar; 1235 1057 pCfg->uOffset = pVirtio->pCommonCfgCap->uOffset + pVirtio->pCommonCfgCap->uLength; 1236 pCfg->uLength = VIRTIO_MAX_QUEUES * uNotifyOffMultiplier + 2; /* will change in VirtIO 1.1 */ 1058 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 2); 1059 pCfg->uLength = VIRTQ_MAX_CNT * VIRTIO_NOTIFY_OFFSET_MULTIPLIER + 2; /* will change in VirtIO 1.1 */ 1237 1060 cbRegion += pCfg->uLength; 1238 1061 pVirtio->pNotifyCap = (PVIRTIO_PCI_NOTIFY_CAP_T)pCfg; 1239 pVirtio->pNotifyCap->uNotifyOffMultiplier = uNotifyOffMultiplier;1240 1241 /* ISR capability (VirtIO 1.0 spec, section 4.1.4.5) */1062 pVirtio->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER; 1063 1064 /** ISR capability (VirtIO 1.0 spec, section 4.1.4.5) */ 1242 1065 pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext]; 1243 1066 pCfg->uCfgType = VIRTIO_PCI_CAP_ISR_CFG; … … 1247 1070 pCfg->uBar = uVirtioCapBar; 1248 1071 pCfg->uOffset = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength; 1249 pCfg->uLength = sizeof( uint32_t);1072 pCfg->uLength = sizeof(VIRTIO_PCI_ISR_CAP_T); 1250 1073 cbRegion += pCfg->uLength; 1251 1074 pVirtio->pIsrCap = pCfg; 1252 1075 1253 /* PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7) */ 1076 /** PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7) 1077 * This capability doesn't get page-MMIO mapped. Instead uBar, uOffset and uLength are intercepted 1078 * by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write 1079 * values from any region. NOTE: The linux driver not only doesn't use this feature, and will not 1080 * even list it as present if uLength isn't non-zero and 4-byte-aligned as the linux driver is initializing */ 1081 1254 1082 pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext]; 1255 1083 pCfg->uCfgType = VIRTIO_PCI_CAP_PCI_CFG; … … 1257 1085 pCfg->uCapLen = sizeof(VIRTIO_PCI_CFG_CAP_T); 1258 1086 pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1259 pCfg->uBar = uVirtioCapBar;1260 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;1261 pCfg->uLength = 4; /* Initialize a non-zero 4-byte aligned so Linux virtio_pci module recognizes this cap */1087 pCfg->uBar = 0; 1088 pCfg->uOffset = 0; 1089 pCfg->uLength = 0; 1262 1090 cbRegion += pCfg->uLength; 1263 1091 pVirtio->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg; … … 1265 1093 if (pVirtio->pDevSpecificCap) 1266 1094 { 1267 /* Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the1268 * device specific configuration struct and passes its paramsto this constructor */1095 /** Following capability (via VirtIO 1.0, section 4.1.4.6). Client defines the 1096 * device-specific config fields struct and passes size to this constructor */ 1269 1097 pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext]; 1270 1098 pCfg->uCfgType = VIRTIO_PCI_CAP_DEVICE_CFG; … … 1274 1102 pCfg->uBar = uVirtioCapBar; 1275 1103 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength; 1104 pCfg->uOffset = RT_ALIGN_32(pCfg->uOffset, 4); 1276 1105 pCfg->uLength = cbDevSpecificCap; 1277 1106 cbRegion += pCfg->uLength; … … 1279 1108 } 1280 1109 1281 /* Set offset to first capability and enable PCI dev capabilities */1110 /** Set offset to first capability and enable PCI dev capabilities */ 1282 1111 PCIDevSetCapabilityList (&pVirtio->dev, 0x40); 1283 1112 PCIDevSetStatus (&pVirtio->dev, VBOX_PCI_STATUS_CAP_LIST); … … 1293 1122 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg); /* see MsixR3init() */ 1294 1123 if (RT_FAILURE (rc)) 1295 /* PK TODO:The following is moot, we need to flag no MSI-X support */1124 /** The following is moot, we need to flag no MSI-X support */ 1296 1125 PCIDevSetCapabilityList(&pVirtio->dev, 0x40); 1297 1126 } 1298 1127 1299 Log(("cbRegion = %d (0x%x)\n", cbRegion, cbRegion)); 1300 rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapBar, cbRegion, 1128 /** Linux drivers/virtio/virtio_pci_modern.c tries to map at least a page for the 1129 * 'unknown' device-specific capability without querying the capability to figure 1130 * out size, so pad with an extra page */ 1131 1132 rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapBar, RT_ALIGN_32(cbRegion + 4096, 4096), 1301 1133 PCI_ADDRESS_SPACE_MEM, virtioR3Map); 1302 1134 if (RT_FAILURE(rc)) … … 1307 1139 N_("virtio: cannot register PCI Capabilities address space")); 1308 1140 } 1309 *phVirtio = ( PVIRTIOHANDLE)pVirtio;1141 *phVirtio = (VIRTIOHANDLE)pVirtio; 1310 1142 return rc; 1311 1143 } 1144 1145 #ifdef VBOX_DEVICE_STRUCT_TESTCASE 1146 # define virtioDumpState(x, s) do {} while (0) 1147 #else 1148 # ifdef DEBUG 1149 1150 static void virtioDumpState(PVIRTIOSTATE pVirtio, const char *pcszCaller) 1151 { 1152 Log2Func(("(called from %s)\n" 1153 " uDeviceFeatures = 0x%08x\n" 1154 " uDriverFeatures = 0x%08x\n" 1155 " uDeviceFeaturesSelect = 0x%04x\n" 1156 " uGuestFeaturesSelect = 0x%04x\n" 1157 " uDeviceStatus = 0x%02x\n" 1158 " uConfigGeneration = 0x%02x\n" 1159 " uQueueSelect = 0x%04x\n" 1160 " uNumQueues = 0x%04x\n" 1161 " uISR = 0x%02x\n" 1162 " fGenUpdatePending = 0x%02x\n" 1163 " uVirtioCapBar = 0x%02x\n" 1164 " uPciCfgDataOff = 0x%02x\n" 1165 " pGcPhysPciCapBase = %RGp\n" 1166 " pGcPhysCommonCfg = %RGp\n" 1167 " pGcPhysNotifyCap = %RGp\n" 1168 " pGcPhysIsrCap = %RGp\n" 1169 " pGcPhysDeviceCap = %RGp\n" 1170 " pDevSpecificCap = %p\n" 1171 " cbDevSpecificCap = 0x%04x\n" 1172 " pfnVirtioStatusChanged = %p\n" 1173 " pfnVirtioDevCapRead = %p\n" 1174 " pfnVirtioDevCapWrite = %p\n" 1175 " pfnPciConfigReadOld = %p\n" 1176 " pfnPciConfigWriteOld = %p\n", 1177 pcszCaller, 1178 pVirtio->uDeviceFeatures, 1179 pVirtio->uDriverFeatures, 1180 pVirtio->uDeviceFeaturesSelect, 1181 pVirtio->uDriverFeaturesSelect, 1182 pVirtio->uDeviceStatus, 1183 pVirtio->uConfigGeneration, 1184 pVirtio->uQueueSelect, 1185 pVirtio->uNumQueues, 1186 pVirtio->uISR, 1187 pVirtio->fGenUpdatePending, 1188 pVirtio->uVirtioCapBar, 1189 pVirtio->uPciCfgDataOff, 1190 pVirtio->pGcPhysPciCapBase, 1191 pVirtio->pGcPhysCommonCfg, 1192 pVirtio->pGcPhysNotifyCap, 1193 pVirtio->pGcPhysIsrCap, 1194 pVirtio->pGcPhysDeviceCap, 1195 pVirtio->pDevSpecificCap, 1196 pVirtio->cbDevSpecificCap, 1197 pVirtio->virtioCallbacks.pfnVirtioStatusChanged, 1198 pVirtio->virtioCallbacks.pfnVirtioDevCapRead, 1199 pVirtio->virtioCallbacks.pfnVirtioDevCapWrite, 1200 pVirtio->pfnPciConfigReadOld, 1201 pVirtio->pfnPciConfigWriteOld 1202 )); 1203 1204 for (uint16_t i = 0; i < pVirtio->uNumQueues; i++) 1205 { 1206 Log2Func(("%s queue:\n", 1207 " queueContext[%u].uNextAvailIdx = %u\n" 1208 " queueContext[%u].uNextUsedIdx = %u\n" 1209 " uQueueSize[%u] = %u\n" 1210 " uQueueNotifyOff[%u] = %04x\n" 1211 " uQueueMsixVector[%u] = %04x\n" 1212 " uQueueEnable[%u] = %04x\n" 1213 " pGcPhysQueueDesc[%u] = %RGp\n" 1214 " pGcPhysQueueAvail[%u] = %RGp\n" 1215 " pGcPhysQueueUsed[%u] = %RGp\n", 1216 i, pVirtio->queueContext[i].pcszName, 1217 i, pVirtio->queueContext[i].uNextAvailIdx, 1218 i, pVirtio->queueContext[i].uNextUsedIdx, 1219 i, pVirtio->uQueueSize[i], 1220 i, pVirtio->uQueueNotifyOff[i], 1221 i, pVirtio->uQueueMsixVector[i], 1222 i, pVirtio->uQueueEnable[i], 1223 i, pVirtio->pGcPhysQueueDesc[i], 1224 i, pVirtio->pGcPhysQueueAvail[i], 1225 i, pVirtio->pGcPhysQueueUsed[i] 1226 )); 1227 } 1228 } 1229 # endif 1230 #endif 1231 1232 #ifdef IN_RING3 1233 1234 /** @callback_method_impl{FNSSMDEVSAVEEXEC} */ 1235 static DECLCALLBACK(int) virtioR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) 1236 { 1237 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 1238 1239 int rc = VINF_SUCCESS; 1240 virtioDumpState(pVirtio, "virtioSaveExec"); 1241 1242 rc = SSMR3PutBool(pSSM, pVirtio->fGenUpdatePending); 1243 rc = SSMR3PutU8(pSSM, pVirtio->uDeviceStatus); 1244 rc = SSMR3PutU8(pSSM, pVirtio->uConfigGeneration); 1245 rc = SSMR3PutU8(pSSM, pVirtio->uPciCfgDataOff); 1246 rc = SSMR3PutU8(pSSM, pVirtio->uVirtioCapBar); 1247 rc = SSMR3PutU8(pSSM, pVirtio->uISR); 1248 rc = SSMR3PutU16(pSSM, pVirtio->uQueueSelect); 1249 rc = SSMR3PutU32(pSSM, pVirtio->uDeviceFeaturesSelect); 1250 rc = SSMR3PutU32(pSSM, pVirtio->uDriverFeaturesSelect); 1251 rc = SSMR3PutU32(pSSM, pVirtio->uNumQueues); 1252 rc = SSMR3PutU32(pSSM, pVirtio->cbDevSpecificCap); 1253 rc = SSMR3PutU64(pSSM, pVirtio->uDeviceFeatures); 1254 rc = SSMR3PutU64(pSSM, pVirtio->uDeviceFeatures); 1255 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->pDevSpecificCap); 1256 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->virtioCallbacks.pfnVirtioStatusChanged); 1257 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->virtioCallbacks.pfnVirtioDevCapRead); 1258 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->virtioCallbacks.pfnVirtioDevCapWrite); 1259 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->pfnPciConfigReadOld); 1260 rc = SSMR3PutU64(pSSM, (uint64_t)pVirtio->pfnPciConfigWriteOld); 1261 rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysCommonCfg); 1262 rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysNotifyCap); 1263 rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysIsrCap); 1264 rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysDeviceCap); 1265 rc = SSMR3PutGCPhys(pSSM, pVirtio->pGcPhysPciCapBase); 1266 1267 for (uint16_t i = 0; i < pVirtio->uNumQueues; i++) 1268 { 1269 rc = SSMR3PutGCPhys64(pSSM, pVirtio->pGcPhysQueueDesc[i]); 1270 rc = SSMR3PutGCPhys64(pSSM, pVirtio->pGcPhysQueueAvail[i]); 1271 rc = SSMR3PutGCPhys64(pSSM, pVirtio->pGcPhysQueueUsed[i]); 1272 rc = SSMR3PutU16(pSSM, pVirtio->uQueueNotifyOff[i]); 1273 rc = SSMR3PutU16(pSSM, pVirtio->uQueueMsixVector[i]); 1274 rc = SSMR3PutU16(pSSM, pVirtio->uQueueEnable[i]); 1275 rc = SSMR3PutU16(pSSM, pVirtio->uQueueSize[i]); 1276 rc = SSMR3PutU16(pSSM, pVirtio->queueContext[i].uNextAvailIdx); 1277 rc = SSMR3PutU16(pSSM, pVirtio->queueContext[i].uNextUsedIdx); 1278 rc = SSMR3PutMem(pSSM, pVirtio->queueContext[i].pcszName, 32); 1279 } 1280 1281 rc = pVirtio->virtioCallbacks.pfnSSMDevSaveExec(pDevIns, pSSM); 1282 return rc; 1283 } 1284 1285 /** @callback_method_impl{FNSSMDEVLOADEXEC} */ 1286 static DECLCALLBACK(int) virtioR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 1287 { 1288 RT_NOREF(uVersion); 1289 1290 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 1291 1292 int rc = VINF_SUCCESS; 1293 virtioDumpState(pVirtio, "virtioLoadExec"); 1294 1295 if (uPass == SSM_PASS_FINAL) 1296 { 1297 rc = SSMR3GetBool(pSSM, &pVirtio->fGenUpdatePending); 1298 rc = SSMR3GetU8(pSSM, &pVirtio->uDeviceStatus); 1299 rc = SSMR3GetU8(pSSM, &pVirtio->uConfigGeneration); 1300 rc = SSMR3GetU8(pSSM, &pVirtio->uPciCfgDataOff); 1301 rc = SSMR3GetU8(pSSM, &pVirtio->uVirtioCapBar); 1302 rc = SSMR3GetU8(pSSM, &pVirtio->uISR); 1303 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueSelect); 1304 rc = SSMR3GetU32(pSSM, &pVirtio->uDeviceFeaturesSelect); 1305 rc = SSMR3GetU32(pSSM, &pVirtio->uDriverFeaturesSelect); 1306 rc = SSMR3GetU32(pSSM, &pVirtio->uNumQueues); 1307 rc = SSMR3GetU32(pSSM, &pVirtio->cbDevSpecificCap); 1308 rc = SSMR3GetU64(pSSM, &pVirtio->uDeviceFeatures); 1309 rc = SSMR3GetU64(pSSM, &pVirtio->uDeviceFeatures); 1310 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->pDevSpecificCap); 1311 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioStatusChanged); 1312 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioDevCapRead); 1313 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->virtioCallbacks.pfnVirtioDevCapWrite); 1314 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->pfnPciConfigReadOld); 1315 rc = SSMR3GetU64(pSSM, (uint64_t *)&pVirtio->pfnPciConfigWriteOld); 1316 rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysCommonCfg); 1317 rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysNotifyCap); 1318 rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysIsrCap); 1319 rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysDeviceCap); 1320 rc = SSMR3GetGCPhys(pSSM, &pVirtio->pGcPhysPciCapBase); 1321 1322 for (uint16_t i = 0; i < pVirtio->uNumQueues; i++) 1323 { 1324 rc = SSMR3GetGCPhys64(pSSM, &pVirtio->pGcPhysQueueDesc[i]); 1325 rc = SSMR3GetGCPhys64(pSSM, &pVirtio->pGcPhysQueueAvail[i]); 1326 rc = SSMR3GetGCPhys64(pSSM, &pVirtio->pGcPhysQueueUsed[i]); 1327 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueNotifyOff[i]); 1328 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueMsixVector[i]); 1329 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueEnable[i]); 1330 rc = SSMR3GetU16(pSSM, &pVirtio->uQueueSize[i]); 1331 rc = SSMR3GetU16(pSSM, &pVirtio->queueContext[i].uNextAvailIdx); 1332 rc = SSMR3GetU16(pSSM, &pVirtio->queueContext[i].uNextUsedIdx); 1333 rc = SSMR3GetMem(pSSM, pVirtio->queueContext[i].pcszName, 32); 1334 } 1335 } 1336 1337 rc = pVirtio->virtioCallbacks.pfnSSMDevLoadExec(pDevIns, pSSM, uVersion, uPass); 1338 1339 return rc; 1340 } 1341 1342 /** @callback_method_impl{FNSSMDEVLOADDONE} */ 1343 static DECLCALLBACK(int) virtioR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) 1344 { 1345 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 1346 1347 int rc = VINF_SUCCESS; 1348 virtioDumpState(pVirtio, "virtioLoadDone"); 1349 1350 rc = pVirtio->virtioCallbacks.pfnSSMDevLoadDone(pDevIns, pSSM); 1351 1352 return rc; 1353 } 1354 1355 /** @callback_method_impl{FNSSMDEVLIVEEXEC} */ 1356 static DECLCALLBACK(int) virtioR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) 1357 { 1358 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 1359 1360 int rc = VINF_SUCCESS; 1361 virtioDumpState(pVirtio, "virtioLiveExec"); 1362 1363 rc = pVirtio->virtioCallbacks.pfnSSMDevLiveExec(pDevIns, pSSM, uPass); 1364 1365 return rc; 1366 1367 } 1368 1369 1312 1370 #endif /* IN_RING3 */ 1313 1371 -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80194 r80219 24 24 #include <iprt/ctype.h> 25 25 26 #define VIRTQ_MAX_SIZE 1024 27 #define VIRTIO_MAX_QUEUES 256 /** Max queues we allow guest to create */ 26 typedef void * VIRTIOHANDLE; /**< Opaque handle to the VirtIO framework */ 27 28 #define DISABLE_GUEST_DRIVER 0 29 30 /** 31 * Important sizing and bounds params for this impl. of VirtIO 1.0 PCI device 32 */ 33 /**** Temporary values for debugging */ 34 #define VIRTQ_MAX_SIZE 16 /**< Max size (# desc elements) of a virtq */ 35 #define VIRTQ_MAX_CNT 24 /**< Max queues we allow guest to create */ 36 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER 2 /**< VirtIO Notify Cap. MMIO config param */ 28 37 #define VIRTQ_DESC_MAX_SIZE (2 * 1024 * 1024) 29 38 30 typedef void * VIRTIOHANDLE; /** opaque handle to the VirtIO framework */ 31 typedef VIRTIOHANDLE *PVIRTIOHANDLE; 32 33 /** Reserved Feature Bits */ 34 #define VIRTIO_F_RING_INDIRECT_DESC RT_BIT_64(28) 35 #define VIRTIO_F_RING_IDX RT_BIT_64(29) 36 #define VIRTIO_F_VERSION_1 RT_BIT_64(32) 37 38 #define VIRTIO_MSI_NO_VECTOR 0xffff /* Vector value used to disable MSI for queue */ 39 40 /** Device Status field constants (from Virtio 1.0 spec) */ 41 #define VIRTIO_STATUS_ACKNOWLEDGE 0x01 /** Guest found this emulated PCI device */ 42 #define VIRTIO_STATUS_DRIVER 0x02 /** Guest can drive this PCI device */ 43 #define VIRTIO_STATUS_DRIVER_OK 0x04 /** Guest VirtIO driver setup and ready */ 44 #define VIRTIO_STATUS_FEATURES_OK 0x08 /** Guest says feature negotiation complete */ 45 #define VIRTIO_STATUS_FAILED 0x80 /** Fatal: Something wrong, guest gave up */ 46 #define VIRTIO_STATUS_DEVICE_NEEDS_RESET 0x40 /** Device experienced unrecoverable error */ 47 48 /** virtq related flags */ 49 #define VIRTQ_DESC_F_NEXT 1 /** Indicates this descriptor chains to next */ 50 #define VIRTQ_DESC_F_WRITE 2 /** Marks buffer as write-only (default ro) */ 51 #define VIRTQ_DESC_F_INDIRECT 4 /** Buffer is list of buffer descriptors */ 52 #define VIRTIO_F_INDIRECT_DESC 28 /** Using indirect descriptors */ 53 #define VIRTIO_F_EVENT_IDX 29 /** avail_event, used_event in play */ 54 55 #define VIRTQ_USED_F_NO_NOTIFY 1 /** Optimization: Device advises driver (unreliably): 56 Don't kick me when adding buffer */ 57 58 #define VIRTQ_AVAIL_F_NO_INTERRUPT 1 /** Optimization: Driver advises device (unreliably): 59 Don't interrupt when buffer consumed */ 60 /** 61 * virtq related structs 62 * (struct names follow VirtIO 1.0 spec, typedef use VBox style) 63 */ 64 typedef struct virtq_desc 65 { 66 uint64_t pGcPhysBuf; /** addr GC physical address of buffer */ 67 uint32_t cbBuf; /** len Buffer length */ 68 uint16_t fFlags; /** flags Buffer specific flags */ 69 uint16_t uNext; /** next Chain idx if VIRTIO_DESC_F_NEXT */ 70 } VIRTQ_DESC_T, *PVIRTQ_DESC_T; 71 72 typedef struct virtq_avail /* VirtIO 1.0 specification formal name of this struct */ 73 { 74 uint16_t fFlags; /** flags avail ring guest-to-host flags */ 75 uint16_t uIdx; /** idx Index of next free ring slot */ 76 uint16_t auRing[1]; /** ring Ring: avail guest-to-host bufs */ 77 uint16_t uUsedEventIdx; /** used_event (if VIRTQ_USED_F_NO_NOTIFY) */ 78 } VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T; 79 80 typedef struct virtq_used_elem /* VirtIO 1.0 specification formal name of this struct */ 81 { 82 uint32_t uIdx; /** idx Start of used descriptor chain */ 83 uint32_t cbElem; /** len Total len of used desc chain */ 84 } VIRTQ_USED_ELEM_T; 85 86 typedef struct virt_used /* VirtIO 1.0 specification formal name of this struct */ 87 { 88 uint16_t fFlags; /** flags used ring host-to-guest flags */ 89 uint16_t uIdx; /** idx Index of next ring slot */ 90 VIRTQ_USED_ELEM_T aRing[1]; /** ring Ring: used host-to-guest bufs */ 91 uint16_t uAvailEventIdx; /** avail_event if (VIRTQ_USED_F_NO_NOTIFY) */ 92 } VIRTQ_USED_T, *PVIRTQ_USED_T; 93 94 95 typedef struct virtq 96 { 97 uint16_t cbQueue; /** virtq size */ 98 uint16_t padding[3]; /** 64-bit-align phys ptrs to start of struct */ 99 RTGCPHYS pGcPhysVirtqDescriptors; /** (struct virtq_desc *) */ 100 RTGCPHYS pGcPhysVirtqAvail; /** (struct virtq_avail *) */ 101 RTGCPHYS pGcPhysVirtqUsed; /** (struct virtq_used *) */ 102 } VIRTQ, *PVIRTQ; 103 104 typedef struct VQueue 105 { 106 VIRTQ VirtQ; 107 uint16_t uNextAvailIndex; 108 uint16_t uNextUsedIndex; 109 uint32_t uPageNumber; 110 R3PTRTYPE(const char *) pcszName; 111 } VQUEUE; 112 113 114 typedef VQUEUE *PVQUEUE; 115 116 typedef struct VQueueElemSeg 117 { 118 RTGCPHYS addr; 119 void *pv; 120 uint32_t cb; 121 } VQUEUESEG; 122 123 typedef struct VQueueElem 124 { 125 uint32_t idx; 126 uint32_t cSegsIn; 127 uint32_t cSegsOut; 128 VQUEUESEG aSegsIn[VIRTQ_MAX_SIZE]; 129 VQUEUESEG aSegsOut[VIRTQ_MAX_SIZE]; 130 } VQUEUEELEM; 131 typedef VQUEUEELEM *PVQUEUEELEM; 39 typedef struct VIRTQ_SEG /**< Describes one segment of a buffer vector */ 40 { 41 RTGCPHYS addr; /**< Physical addr. of this segment's buffer */ 42 void *pv; /**< Buf to hold value to write or read */ 43 uint32_t cb; /**< Number of bytes to write or read */ 44 } VIRTQ_SEG_T; 45 46 typedef struct VIRTQ_BUF_VECTOR /**< Scatter/gather buffer vector */ 47 { 48 uint32_t uDescIdx; /**< Desc at head of this vector list */ 49 uint32_t cSegsIn; /**< Count of segments in aSegsIn[] */ 50 uint32_t cSegsOut; /**< Count of segments in aSegsOut[] */ 51 VIRTQ_SEG_T aSegsIn[VIRTQ_MAX_SIZE]; /**< List of segments to write to guest */ 52 VIRTQ_SEG_T aSegsOut[VIRTQ_MAX_SIZE]; /**< List of segments read from guest */ 53 } VIRTQ_BUF_VECTOR_T, *PVIRTQ_BUF_VECTOR_T; 132 54 133 55 /** 134 56 * The following structure is used to pass the PCI parameters from the consumer 135 * to this generic VirtIO framework 57 * to this generic VirtIO framework. This framework provides the Vendor ID as Virtio. 136 58 */ 137 59 typedef struct VIRTIOPCIPARAMS 138 60 { 139 uint16_t uDeviceId; 140 uint16_t uClassBase; 141 uint16_t uClassSub; 142 uint16_t uClassProg; 143 uint16_t uSubsystemId; 144 uint16_t uSubsystemVendorId; 145 uint16_t uRevisionId; 146 uint16_t uInterruptLine; 147 uint16_t uInterruptPin; 61 uint16_t uDeviceId; /**< PCI Cfg Device ID */ 62 uint16_t uClassBase; /**< PCI Cfg Base Class */ 63 uint16_t uClassSub; /**< PCI Cfg Subclass */ 64 uint16_t uClassProg; /**< PCI Cfg Programming Interface Class */ 65 uint16_t uSubsystemId; /**< PCI Cfg Card Manufacturer Vendor ID */ 66 uint16_t uSubsystemVendorId; /**< PCI Cfg Chipset Manufacturer Vendor ID */ 67 uint16_t uRevisionId; /**< PCI Cfg Revision ID */ 68 uint16_t uInterruptLine; /**< PCI Cfg Interrupt line */ 69 uint16_t uInterruptPin; /**< PCI Cfg InterruptPin */ 148 70 } VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS; 149 71 72 /** 73 * Implementation-specific client callback to notify client of significant device status 74 * changes. 75 * 76 * @param hVirtio Handle to VirtIO framework 77 * @param fDriverOk True if guest driver is okay (thus queues, etc... are valid) 78 */ 79 typedef DECLCALLBACK(void) FNVIRTIOSTATUSCHANGED(VIRTIOHANDLE hVirtio, bool fDriverOk); 80 typedef FNVIRTIOSTATUSCHANGED *PFNVIRTIOSTATUSCHANGED; 81 82 /** 83 * When guest-to-host queue notifications are enabled, the guest driver notifies the host 84 * that the avail queue has buffers, and this callback informs the client. 85 * 86 * @param hVirtio Handle to the VirtIO framework 87 * @param qIdx Index of the notified queue 88 */ 89 typedef DECLCALLBACK(void) FNVIRTIOQUEUENOTIFIED(VIRTIOHANDLE hVirtio, uint16_t qIdx); 90 typedef FNVIRTIOQUEUENOTIFIED *PFNVIRTIOQUEUENOTIFIED; 91 150 92 /** 151 * VirtIO Device-specific capabilities read callback93 * Implementation-specific client callback to access VirtIO Device-specific capabilities 152 94 * (other VirtIO capabilities and features are handled in VirtIO implementation) 153 95 * … … 161 103 162 104 /** 163 * VirtIO Device-specific capabilities read callback105 * Implementation-specific client ballback to access VirtIO Device-specific capabilities 164 106 * (other VirtIO capabilities and features are handled in VirtIO implementation) 165 107 * … … 172 114 typedef FNVIRTIODEVCAPREAD *PFNVIRTIODEVCAPREAD; 173 115 116 174 117 /** @name VirtIO port I/O callbacks. 175 118 * @{ */ 176 119 typedef struct VIRTIOCALLBACKS 177 120 { 178 DECLCALLBACKMEMBER(int, pfnVirtioDevCapRead) 179 (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbRead); 180 DECLCALLBACKMEMBER(int, pfnVirtioDevCapWrite) 181 (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbWrite); 121 DECLCALLBACKMEMBER(void, pfnVirtioStatusChanged) 122 (VIRTIOHANDLE hVirtio, bool fDriverOk); 123 DECLCALLBACKMEMBER(void, pfnVirtioQueueNotified) 124 (VIRTIOHANDLE hVirtio, uint16_t qIdx); 125 DECLCALLBACKMEMBER(int, pfnVirtioDevCapRead) 126 (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbRead); 127 DECLCALLBACKMEMBER(int, pfnVirtioDevCapWrite) 128 (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbWrite); 129 DECLCALLBACKMEMBER(int, pfnSSMDevLiveExec) 130 (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass); 131 DECLCALLBACKMEMBER(int, pfnSSMDevSaveExec) 132 (PPDMDEVINS pDevIns, PSSMHANDLE pSSM); 133 DECLCALLBACKMEMBER(int, pfnSSMDevLoadExec) 134 (PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); 135 DECLCALLBACKMEMBER(int, pfnSSMDevLoadDone) 136 (PPDMDEVINS pDevIns, PSSMHANDLE pSSM); 137 182 138 } VIRTIOCALLBACKS, *PVIRTIOCALLBACKS; 183 139 /** @} */ 184 140 185 PVQUEUE virtioAddQueue( VIRTIOHANDLE hVirtio, uint32_t uSize, const char *pcszName); 186 int virtioDestruct( VIRTIOHANDLE hVirtio); 187 int virtioReset( VIRTIOHANDLE hVirtio); 188 void virtioSetReadLed( VIRTIOHANDLE hVirtio, bool fOn); 189 void virtioSetWriteLed( VIRTIOHANDLE hVirtio, bool fOn); 190 int virtioRaiseInterrupt( VIRTIOHANDLE hVirtio, int rcBusy, uint8_t uint8_tIntCause); 191 //void virtioNotifyDriver( VIRTIOHANDLE hVirtio); 192 void virtioSetHostFeatures( VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures); 193 194 bool virtQueueSkip( VIRTIOHANDLE hVirtio, PVQUEUE pQueue); 195 bool virtQueueGet( VIRTIOHANDLE hVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true); 196 void virtQueuePut( VIRTIOHANDLE hVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t len, uint32_t uReserved = 0); 197 void virtQueueNotify( VIRTIOHANDLE hVirtio, PVQUEUE pQueue); 198 void virtQueueSync( VIRTIOHANDLE hVirtio, PVQUEUE pQueue); 199 void vringSetNotification( VIRTIOHANDLE hVirtio, PVIRTQ pVirtQ, bool fEnabled); 200 201 /** 202 * Formats the logging of a memory-mapped I/O input or output value 141 int virtioReset (VIRTIOHANDLE hVirtio); 142 bool virtioQueueInit (VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName); 143 const char * virtioQueueGetName (VIRTIOHANDLE hVirtio, uint16_t qIdx); 144 bool virtioQueueGet (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, bool fRemove); 145 void virtioQueuePut (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec, uint32_t cb); 146 bool virtioQueuePeek (VIRTIOHANDLE hVirtio, uint16_t qIdx, PVIRTQ_BUF_VECTOR_T pBufVec); 147 void virtioQueueSync (VIRTIOHANDLE hVirtio, uint16_t qIdx); 148 bool virtioQueueIsEmpty (VIRTIOHANDLE hVirtio, uint16_t qIdx); 149 int virtioGetNumQueues (VIRTIOHANDLE hVirtio); 150 151 /** CLIENT MUST CALL ON RELOCATE CALLBACK! */ 152 void virtioRelocate( PPDMDEVINS pDevIns, RTGCINTPTR offDelta); 153 154 /** 155 * Log memory-mapped I/O input or output value 203 156 * 204 157 * @param pszFunc - To avoid displaying this function's name via __FUNCTION__ or LogFunc() … … 211 164 * @param idx - The index if fHasIndex 212 165 */ 213 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, 166 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, size_t uMemberSize, 214 167 const void *pv, uint32_t cb, uint32_t uOffset, 215 168 bool fWrite, bool fHasIndex, uint32_t idx); 216 169 217 int virtioConstruct( 218 PPDMDEVINS pDevIns, 219 PVIRTIOHANDLE phVirtio, 220 int iInstance, 221 PVIRTIOPCIPARAMS pPciParams, 222 const char *pcszNameFmt, 223 uint32_t nQueues, 224 uint32_t uVirtioCapBar, 225 uint64_t uDeviceFeatures, 226 PFNVIRTIODEVCAPREAD devCapReadCallback, 227 PFNVIRTIODEVCAPWRITE devCapWriteCallback, 228 uint16_t cbDevSpecificCap, 229 void *pDevSpecificCap, 230 uint32_t uNotifyOffMultiplier); 231 232 //PCIDevGetCapabilityList 233 //PCIDevSetCapabilityList 234 //DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset) 235 // PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset); 236 //DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PPDMPCIDEV pPciDev) 237 // return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST); 170 /** 171 * Setup PCI device controller and Virtio state 172 * 173 * @param pDevIns Device instance data 174 * @param pVirtio Device State 175 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure 176 * @param pcszInstance Device instance name 177 * @param uNumQueues Number of Virtio Queues created by consumer (driver) 178 * @param uVirtioCapBar Region number to map for PCi Capabilities structs 179 * @param uDevSpecificFeatures VirtIO device-specific features offered by client 180 * @param devCapReadCallback Client handler to call upon guest read to device specific capabilities. 181 * @param devCapWriteCallback Client handler to call upon guest write to device specific capabilities. 182 * @param devStatusChangedCallback Client handler to call for major device status changes 183 * @param queueNotifiedCallback Client handler for guest-to-host notifications that avail queue has ring data 184 * @param ssmLiveExecCallback Client handler for SSM live exec 185 * @param ssmSaveExecCallback Client handler for SSM save exec 186 * @param ssmLoadExecCallback Client handler for SSM load exec 187 * @param ssmLoadDoneCallback Client handler for SSM load done 188 * @param cbDevSpecificCap Size of virtio_pci_device_cap device-specific struct 189 */ 190 int virtioConstruct(PPDMDEVINS pDevIns, 191 VIRTIOHANDLE *phVirtio, 192 PVIRTIOPCIPARAMS pPciParams, 193 const char *pcszInstance, 194 uint32_t nQueues, 195 uint32_t uVirtioCapBar, 196 uint64_t uDevSpecificFeatures, 197 PFNVIRTIODEVCAPREAD devCapReadCallback, 198 PFNVIRTIODEVCAPWRITE devCapWriteCallback, 199 PFNVIRTIOSTATUSCHANGED devStatusChangedCallback, 200 PFNVIRTIOQUEUENOTIFIED queueNotifiedCallback, 201 PFNSSMDEVLIVEEXEC ssmLiveExecCallback, 202 PFNSSMDEVSAVEEXEC ssmSaveExecCallback, 203 PFNSSMDEVLOADEXEC ssmLoadExecCallback, 204 PFNSSMDEVLOADDONE ssmLoadDoneCallback, 205 uint16_t cbDevSpecificCap, 206 void *pDevSpecificCap); 238 207 239 208 #endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_h */ -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r80201 r80219 24 24 #include "Virtio_1_0.h" 25 25 26 27 28 26 /** @name Saved state versions. 29 27 * The saved state version is changed if either common or any of specific … … 32 30 * for example. 33 31 */ 34 #define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1 35 #define VIRTIO_SAVEDSTATE_VERSION 2 32 #define VIRTIO_SAVEDSTATE_VERSION 1 36 33 /** @} */ 37 34 38 #define DEVICE_PCI_VENDOR_ID_VIRTIO 0x1AF4 /** Mandatory, so VirtIO driver can find this device */ 39 #define DEVICE_PCI_REVISION_ID_VIRTIO 1 /** Virtio spec suggests >= 1 for non-transitional drivers */ 40 35 #define VIRTIO_ISR_VIRTQ_INTERRUPT RT_BIT_32(0) 36 #define VIRTIO_ISR_DEVICE_CONFIG RT_BIT_32(1) 37 #define DEVICE_PCI_VENDOR_ID_VIRTIO 0x1AF4 /**< Required: VirtIO driver uses to find dev */ 38 #define DEVICE_PCI_REVISION_ID_VIRTIO 1 /**< VirtIO 1.0 non-transitional drivers >= 1 */ 39 40 /** Reserved (*negotiated*) Feature Bits (e.g. device independent features, VirtIO 1.0 spec,section 6) */ 41 42 #define VIRTIO_F_RING_INDIRECT_DESC RT_BIT_64(28) /**< Allow descs to point to list of descs */ 43 #define VIRTIO_F_INDIRECT_DESC RT_BIT_64(28) /**< Doc bug: Bit has 2 names in VirtIO 1.0-04 */ 44 #define VIRTIO_F_RING_EVENT_IDX RT_BIT_64(29) /**< Allow notification disable for n elems */ 45 #define VIRTIO_F_EVENT_IDX RT_BIT_64(29) /**< Doc bug: Bit has 2 names in VirtIO 1.0-04 */ 46 #define VIRTIO_F_VERSION_1 RT_BIT_64(32) 47 48 #define VIRTIO_MSI_NO_VECTOR 0xffff /**< Vector value to disable MSI for queue */ 49 50 /** Device Status field constants (from Virtio 1.0 spec) */ 51 #define VIRTIO_STATUS_ACKNOWLEDGE 0x01 /**< Guest driver: Located this VirtIO device */ 52 #define VIRTIO_STATUS_DRIVER 0x02 /**< Guest driver: Can drive this VirtIO dev. */ 53 #define VIRTIO_STATUS_DRIVER_OK 0x04 /**< Guest driver: Driver set-up and ready */ 54 #define VIRTIO_STATUS_FEATURES_OK 0x08 /**< Guest driver: Feature negotiation done */ 55 #define VIRTIO_STATUS_FAILED 0x80 /**< Guest driver: Fatal error, gave up */ 56 #define VIRTIO_STATUS_DEVICE_NEEDS_RESET 0x40 /**< Device experienced unrecoverable error */ 57 58 /* @def Virtio Device PCI Capabilities type codes */ 59 #define VIRTIO_PCI_CAP_COMMON_CFG 1 /**< Common configuration PCI capability ID */ 60 #define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /**< Notification area PCI capability ID */ 61 #define VIRTIO_PCI_CAP_ISR_CFG 3 /**< ISR PCI capability id */ 62 #define VIRTIO_PCI_CAP_DEVICE_CFG 4 /**< Device-specific PCI cfg capability ID */ 63 #define VIRTIO_PCI_CAP_PCI_CFG 5 /**< PCI CFG capability ID */ 64 65 #define VIRTIO_PCI_CAP_ID_VENDOR 0x09 /**< Vendor-specific PCI CFG Device Cap. ID */ 41 66 42 67 /** 43 68 * The following is the PCI capability struct common to all VirtIO capability types 44 69 */ 45 #define VIRTIO_PCI_CAP_ID_VENDOR 0x09 /** Vendor-specific PCI CFG Device Capability ID */46 47 70 typedef struct virtio_pci_cap 48 71 { 49 72 /* All little-endian */ 50 uint8_t uCapVndr; /** Generic PCI field: PCI_CAP_ID_VNDR*/51 uint8_t uCapNext; /** Generic PCI field: next ptr.*/52 uint8_t uCapLen; /** Generic PCI field: capability length*/53 uint8_t uCfgType; /** Identifies the structure.*/54 uint8_t uBar; /** Where to find it.*/55 uint8_t uPadding[3]; /** Pad to full dword.*/56 uint32_t uOffset; /** Offset within bar. (L.E.)*/57 uint32_t uLength; /** Length of struct, in bytes. (L.E.)*/73 uint8_t uCapVndr; /**< Generic PCI field: PCI_CAP_ID_VNDR */ 74 uint8_t uCapNext; /**< Generic PCI field: next ptr. */ 75 uint8_t uCapLen; /**< Generic PCI field: capability length */ 76 uint8_t uCfgType; /**< Identifies the structure. */ 77 uint8_t uBar; /**< Where to find it. */ 78 uint8_t uPadding[3]; /**< Pad to full dword. */ 79 uint32_t uOffset; /**< Offset within bar. (L.E.) */ 80 uint32_t uLength; /**< Length of struct, in bytes. (L.E.) */ 58 81 } VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T; 59 82 60 83 /** 61 * The following structs correspond to the VirtIO capability types and describe 62 * fields accessed by MMIO via the relevant BAR. virtio_pci_dev_cap is not listed 63 * here because it is device specific, thus the device specific implementation 64 * consumer of this framework passes a ref/size in the constructor 84 * Local implementation's per-queue usage (e.g. not part of VirtIO specification) 85 */ 86 typedef struct VIRTQ_CONTEXT 87 { 88 const char *pcszName[32]; /**< Dev-specific name of queue */ 89 uint16_t uNextAvailIdx; /**< Consumer's position in avail ring */ 90 uint16_t uNextUsedIdx; /**< Consumer's position in used ring */ 91 } VIRTQ_CONTEXT_T, *PVIRTQ_CONTEXT_T; 92 93 /** 94 * VirtIO 1.0 Capabilities' related MMIO-mapped structs: 65 95 * 66 */ 67 68 /* Virtio Device PCI Capabilities type codes */ 69 #define VIRTIO_PCI_CAP_COMMON_CFG 1 /** Common configuration PCI capability ID */ 70 #define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /** Notification area PCI capability ID */ 71 #define VIRTIO_PCI_CAP_ISR_CFG 3 /** ISR PCI capability id */ 72 #define VIRTIO_PCI_CAP_DEVICE_CFG 4 /** Device specific configuration PCI capability ID */ 73 #define VIRTIO_PCI_CAP_PCI_CFG 5 /** PCI CFG capability ID */ 74 75 typedef struct virtio_pci_common_cfg /* VirtIO 1.0 specification name of this struct */ 96 * Note: virtio_pci_device_cap is dev-specific, implemented by client. Definition unknown here. 97 */ 98 typedef struct virtio_pci_common_cfg 76 99 { 77 100 /* Per device fields */ 78 uint32_t uDeviceFeaturesSelect; /** RW (driver selects device features)*/79 uint32_t uDeviceFeatures; /** RO (device reports features to driver)*/80 uint32_t uDriverFeaturesSelect; /** RW (driver selects driver features)*/81 uint32_t uDriverFeatures; /** RW (driver accepts device features)*/82 uint16_t uMsixConfig; /** RW (driver sets MSI-X config vector)*/83 uint16_t uNumQueues; /** RO (device specifies max queues)*/84 uint8_t uDeviceStatus; /** RW (driver writes device status, 0 resets)*/85 uint8_t uConfigGeneration; /** RO (device changes when changing configs)*/101 uint32_t uDeviceFeaturesSelect; /**< RW (driver selects device features) */ 102 uint32_t uDeviceFeatures; /**< RO (device reports features to driver) */ 103 uint32_t uDriverFeaturesSelect; /**< RW (driver selects driver features) */ 104 uint32_t uDriverFeatures; /**< RW (driver accepts device features) */ 105 uint16_t uMsixConfig; /**< RW (driver sets MSI-X config vector) */ 106 uint16_t uNumQueues; /**< RO (device specifies max queues) */ 107 uint8_t uDeviceStatus; /**< RW (driver writes device status, 0 resets)*/ 108 uint8_t uConfigGeneration; /**< RO (device changes when changing configs) */ 86 109 87 110 /* Per virtqueue fields (as determined by uQueueSelect) */ 88 uint16_t uQueueSelect; /** RW (selects queue focus for these fields)*/89 uint16_t uQueueSize; /** RW (queue size, 0 - 2^n)*/90 uint16_t uQueueMsixVector; /** RW (driver selects MSI-X queue vector)*/91 uint16_t uQueueEnable; /** RW (driver controls usability of queue)*/92 uint16_t uQueueNotifyOff; /** RO (offset uto virtqueue; see spec)*/93 uint64_t uQueueDesc; /** RW (driver writes desc table phys addr)*/94 uint64_t uQueueAvail; /** RW (driver writes avail ring phys addr)*/95 uint64_t uQueueUsed; /** RW (driver writes used ring phys addr)*/111 uint16_t uQueueSelect; /**< RW (selects queue focus for these fields) */ 112 uint16_t uQueueSize; /**< RW (queue size, 0 - 2^n) */ 113 uint16_t uQueueMsixVector; /**< RW (driver selects MSI-X queue vector) */ 114 uint16_t uQueueEnable; /**< RW (driver controls usability of queue) */ 115 uint16_t uQueueNotifyOff; /**< RO (offset uto virtqueue; see spec) */ 116 uint64_t pGcPhysQueueDesc; /**< RW (driver writes desc table phys addr) */ 117 uint64_t pGcPhysQueueAvail; /**< RW (driver writes avail ring phys addr) */ 118 uint64_t pGcPhysQueueUsed; /**< RW (driver writes used ring phys addr) */ 96 119 } VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T; 97 120 98 121 typedef struct virtio_pci_notify_cap 99 122 { 100 struct virtio_pci_cap pciCap; 101 uint32_t uNotifyOffMultiplier; /* notify_off_multiplier*/102 } VIRTIO_PCI_NOTIFY_CAP_T,*PVIRTIO_PCI_NOTIFY_CAP_T;123 struct virtio_pci_cap pciCap; /**< Notification MMIO mapping capability */ 124 uint32_t uNotifyOffMultiplier; /**< notify_off_multiplier */ 125 } VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T; 103 126 104 127 typedef struct virtio_pci_cfg_cap 105 128 { 106 struct virtio_pci_cap pciCap; 107 uint8_t uPciCfgData[4]; /* Data for BAR access. */ 108 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T; 129 struct virtio_pci_cap pciCap; /**< Cap. defines the BAR/off/len to access */ 130 uint8_t uPciCfgData[4]; /**< I/O buf for above cap. */ 131 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T; 132 133 /** For ISR, spec says min. 1 byte. Diagram shows 32-bits, mostly reserved */ 134 typedef uint32_t VIRTIO_PCI_ISR_CAP_T, *PVIRTIO_PCI_ISR_CAP_T; 109 135 110 136 /** … … 115 141 typedef struct VIRTIOSTATE 116 142 { 117 PDMPCIDEV dev; 118 PDMCRITSECT cs; /**< Critical section - what is it protecting? */ 119 /* Read-only part, never changes after initialization. */ 120 char szInstance[8]; /**< Instance name, e.g. VNet#1. */ 121 122 #if HC_ARCH_BITS != 64 123 uint32_t padding1; 124 #endif 125 126 /** Status LUN: Base interface. */ 127 PDMIBASE IBase; 128 129 /** Status LUN: LED port interface. */ 130 PDMILEDPORTS ILed; 131 132 /* Read/write part, protected with critical section. */ 133 /** Status LED. */ 134 PDMLED led; 135 136 VIRTIOCALLBACKS virtioCallbacks; 137 138 /** Status LUN: LED connector (peer). */ 139 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector; 140 141 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3. */ 142 PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0. */ 143 PPDMDEVINSRC pDevInsRC; /**< Device instance - RC. */ 144 145 146 uint8_t uPciCfgDataOff; 147 #if HC_ARCH_BITS == 64 148 uint32_t padding2; 149 #endif 150 151 /** Base port of I/O space region. */ 152 RTIOPORT IOPortBase; 153 154 uint32_t uGuestFeatures; 155 uint16_t uQueueSelector; /** An index in aQueues array. */ 156 uint8_t uStatus; /** Device Status (bits are device-specific). */ 157 uint8_t uISR; /** Interrupt Status Register. */ 158 159 #if HC_ARCH_BITS != 64 160 uint32_t padding3; 161 #endif 162 163 VQUEUE Queues[VIRTIO_MAX_QUEUES]; 164 uint32_t uNotifyOffMultiplier; /* Multiplier for uQueueNotifyOff[idx] */ 165 166 /** Whole virtio device */ 167 uint32_t uDeviceFeaturesSelect; /** Select hi/lo 32-bit uDeviceFeatures to r/w */ 168 uint64_t uDeviceFeatures; /** Host features offered */ 169 uint32_t uDriverFeaturesSelect; /** Selects hi/lo 32-bit uDriverFeatures to r/w*/ 170 uint64_t uDriverFeatures; /** Host features accepted by guest */ 171 uint32_t uMsixConfig; 172 uint32_t uNumQueues; /** Actual number of queues used. */ 173 uint8_t uDeviceStatus; 174 uint8_t uConfigGeneration; 175 176 /** Specific virtqueue */ 177 uint16_t uQueueSelect; 178 uint16_t uQueueSize[VIRTIO_MAX_QUEUES]; /** Device sets on reset, driver can modify */ 179 uint16_t uQueueNotifyOff[VIRTIO_MAX_QUEUES]; /** Device sets this */ 180 uint16_t uQueueMsixVector[VIRTIO_MAX_QUEUES]; /** Driver specifies queue vector for MSI-X */ 181 uint16_t uQueueEnable[VIRTIO_MAX_QUEUES]; /** Driver controls device access to queue */ 182 uint64_t uQueueDesc[VIRTIO_MAX_QUEUES]; /** Driver provides this */ 183 uint64_t uQueueAvail[VIRTIO_MAX_QUEUES]; /** Driver provides this */ 184 uint64_t uQueueUsed[VIRTIO_MAX_QUEUES]; /** Driver provides this */ 185 186 187 uint8_t uVirtioCapBar; /* Capabilities BAR (region) assigned by client */ 188 189 /** Callbacks when guest driver reads or writes VirtIO device-specific capabilities(s) */ 190 PFNPCICONFIGREAD pfnPciConfigReadOld; 191 PFNPCICONFIGWRITE pfnPciConfigWriteOld; 192 193 uint32_t cbDevSpecificCap; /* Size of client's dev-specific config data */ 194 void *pDevSpecificCap; /* Pointer to client's struct */ 195 void *pPrevDevSpecificCap; /* Previous read dev-specific cfg of client */ 196 bool fGenUpdatePending; /* If set, update cfg gen. after driver reads */ 197 198 PVIRTIO_PCI_CFG_CAP_T pPciCfgCap; /** Pointer to struct in configuration area */ 199 PVIRTIO_PCI_NOTIFY_CAP_T pNotifyCap; /** Pointer to struct in configuration area */ 200 PVIRTIO_PCI_CAP_T pCommonCfgCap; /** Pointer to struct in configuration area */ 201 PVIRTIO_PCI_CAP_T pIsrCap; /** Pointer to struct in configuration area */ 202 PVIRTIO_PCI_CAP_T pDeviceCap; /** Pointer to struct in configuration area */ 203 204 /** Base address of PCI capabilities */ 205 RTGCPHYS GCPhysPciCapBase; 206 RTGCPHYS pGcPhysCommonCfg; /** Pointer to MMIO mapped capability data */ 207 RTGCPHYS pGcPhysNotifyCap; /** Pointer to MMIO mapped capability data */ 208 RTGCPHYS pGcPhysIsrCap; /** Pointer to MMIO mapped capability data */ 209 RTGCPHYS pGcPhysDeviceCap; /** Pointer to MMIO mapped capability data */ 210 211 bool fDeviceConfigInterrupt; 212 bool fQueueInterrupt; 143 PDMPCIDEV dev; /**< PCI device */ 144 char szInstance[16]; /**< Instance name, e.g. "VIRTIOSCSI0" */ 145 146 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3 */ 147 PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0 */ 148 PPDMDEVINSRC pDevInsRC; /**< Device instance - RC */ 149 150 RTGCPHYS pGcPhysPciCapBase; /**< Pointer to MMIO mapped capability data */ 151 RTGCPHYS pGcPhysCommonCfg; /**< Pointer to MMIO mapped capability data */ 152 RTGCPHYS pGcPhysNotifyCap; /**< Pointer to MMIO mapped capability data */ 153 RTGCPHYS pGcPhysIsrCap; /**< Pointer to MMIO mapped capability data */ 154 RTGCPHYS pGcPhysDeviceCap; /**< Pointer to MMIO mapped capability data */ 155 156 RTGCPHYS pGcPhysQueueDesc[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q desc structs GUEST */ 157 RTGCPHYS pGcPhysQueueAvail[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q avail structs GUEST */ 158 RTGCPHYS pGcPhysQueueUsed[VIRTQ_MAX_CNT]; /**< (MMIO) PhysAdr per-Q used structs GUEST */ 159 uint16_t uQueueNotifyOff[VIRTQ_MAX_CNT]; /**< (MMIO) per-Q notify offset HOST */ 160 uint16_t uQueueMsixVector[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue vector for MSI-X GUEST */ 161 uint16_t uQueueEnable[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue enable GUEST */ 162 uint16_t uQueueSize[VIRTQ_MAX_CNT]; /**< (MMIO) Per-queue size HOST/GUEST */ 163 uint16_t uQueueSelect; /**< (MMIO) queue selector GUEST */ 164 uint16_t padding; 165 uint64_t uDeviceFeatures; /**< (MMIO) Host features offered HOST */ 166 uint64_t uDriverFeatures; /**< (MMIO) Host features accepted GUEST */ 167 uint32_t uDeviceFeaturesSelect; /**< (MMIO) hi/lo select uDeviceFeatures GUEST */ 168 uint32_t uDriverFeaturesSelect; /**< (MMIO) hi/lo select uDriverFeatures GUEST */ 169 uint32_t uMsixConfig; /**< (MMIO) MSI-X vector GUEST */ 170 uint32_t uNumQueues; /**< (MMIO) Actual number of queues GUEST */ 171 uint8_t uDeviceStatus; /**< (MMIO) Device Status GUEST */ 172 uint8_t uConfigGeneration; /**< (MMIO) Device config sequencer HOST */ 173 174 VIRTQ_CONTEXT_T queueContext[VIRTQ_MAX_CNT]; /**< Local impl-specific queue context */ 175 VIRTIOCALLBACKS virtioCallbacks; /**< Callback vectors to client */ 176 177 PFNPCICONFIGREAD pfnPciConfigReadOld; /**< Prev rd. cb. intercepting PCI Cfg I/O */ 178 PFNPCICONFIGWRITE pfnPciConfigWriteOld; /**< Prev wr. cb. intercepting PCI Cfg I/O */ 179 180 PVIRTIO_PCI_CFG_CAP_T pPciCfgCap; /**< Pointer to struct in configuration area */ 181 PVIRTIO_PCI_NOTIFY_CAP_T pNotifyCap; /**< Pointer to struct in configuration area */ 182 PVIRTIO_PCI_CAP_T pCommonCfgCap; /**< Pointer to struct in configuration area */ 183 PVIRTIO_PCI_CAP_T pIsrCap; /**< Pointer to struct in configuration area */ 184 PVIRTIO_PCI_CAP_T pDeviceCap; /**< Pointer to struct in configuration area */ 185 186 uint32_t cbDevSpecificCap; /**< Size of client's dev-specific config data */ 187 void *pDevSpecificCap; /**< Pointer to client's struct */ 188 void *pPrevDevSpecificCap; /**< Previous read dev-specific cfg of client */ 189 bool fGenUpdatePending; /**< If set, update cfg gen after driver reads */ 190 uint8_t uPciCfgDataOff; 191 uint8_t uVirtioCapBar; /**< Capabilities BAR/region (client-assigned) */ 192 uint8_t uISR; /**< Interrupt Status Register. */ 213 193 214 194 } VIRTIOSTATE, *PVIRTIOSTATE; 215 195 216 DECLINLINE(uint16_t) vringReadAvail(PVIRTIOSTATE pVirtio, PVIRTQ pVirtQ) 217 { 218 uint16_t dataWord; 219 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 220 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx), 221 &dataWord, sizeof(dataWord)); 222 return dataWord; 223 } 224 225 DECLINLINE(bool) virtQueuePeek(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem) 226 { 227 return virtQueueGet(pVirtio, pQueue, pElem, /* fRemove */ false); 228 } 229 230 DECLINLINE(bool) virtQueueIsReady(PVIRTIOSTATE pVirtio, PVQUEUE pQueue) 231 { 232 NOREF(pVirtio); 233 return !!pQueue->VirtQ.pGcPhysVirtqAvail; 234 } 235 236 DECLINLINE(bool) virtQueueIsEmpty(PVIRTIOSTATE pVirtio, PVQUEUE pQueue) 237 { 238 return (vringReadAvail(pVirtio, &pQueue->VirtQ) == pQueue->uNextAvailIndex); 239 } 196 /** virtq related flags */ 197 #define VIRTQ_DESC_F_NEXT 1 /**< Indicates this descriptor chains to next */ 198 #define VIRTQ_DESC_F_WRITE 2 /**< Marks buffer as write-only (default ro) */ 199 #define VIRTQ_DESC_F_INDIRECT 4 /**< Buffer is list of buffer descriptors */ 200 201 #define VIRTQ_USED_F_NO_NOTIFY 1 /**< Dev to Drv: Don't notify when buf added */ 202 #define VIRTQ_AVAIL_F_NO_INTERRUPT 1 /**< Drv to Dev: Don't notify when buf eaten */ 203 204 /** 205 * virtq related structs 206 * (struct names follow VirtIO 1.0 spec, typedef use VBox style) 207 */ 208 typedef struct virtq_desc 209 { 210 uint64_t pGcPhysBuf; /**< addr GC Phys. address of buffer */ 211 uint32_t cb; /**< len Buffer length */ 212 uint16_t fFlags; /**< flags Buffer specific flags */ 213 uint16_t uDescIdxNext; /**< next Idx set if VIRTIO_DESC_F_NEXT */ 214 } VIRTQ_DESC_T, *PVIRTQ_DESC_T; 215 216 typedef struct virtq_avail 217 { 218 uint16_t fFlags; /**< flags avail ring drv to dev flags */ 219 uint16_t uDescIdx; /**< idx Index of next free ring slot */ 220 uint16_t auRing[1]; /**< ring Ring: avail drv to dev bufs */ 221 uint16_t uUsedEventIdx; /**< used_event (if VIRTQ_USED_F_NO_NOTIFY) */ 222 } VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T; 223 224 typedef struct virtq_used_elem 225 { 226 uint32_t uDescIdx; /**< idx Start of used desc chain */ 227 uint32_t cbElem; /**< len Total len of used desc chain */ 228 } VIRTQ_USED_ELEM_T; 229 230 typedef struct virt_used 231 { 232 uint16_t fFlags; /**< flags used ring host-to-guest flags */ 233 uint16_t uDescIdx; /**< idx Index of next ring slot */ 234 VIRTQ_USED_ELEM_T auRing[1]; /**< ring Ring: used dev to drv bufs */ 235 uint16_t uAvailEventIdx; /**< avail_event if (VIRTQ_USED_F_NO_NOTIFY) */ 236 } VIRTQ_USED_T, *PVIRTQ_USED_T; 237 240 238 /** 241 239 * This macro returns true if physical address and access length are within the mapped capability struct. … … 249 247 * @param GCPhysAddr - [input, implied] Physical address accessed (via MMIO callback) 250 248 * @param cb - [input, implied] Number of bytes to access 251 *252 249 */ 253 250 #define MATCH_VIRTIO_CAP_STRUCT(pGcPhysCapData, pCfgCap, fMatched) \ … … 268 265 * @result - true or false 269 266 */ 270 #define COMMON_CFG(member) \267 #define MATCH_COMMON_CFG(member) \ 271 268 (RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member) == 8 \ 272 269 && ( uOffset == RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member) \ … … 276 273 && cb == RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member)) 277 274 278 #define LOG_ACCESSOR(member) \ 279 virtioLogMappedIoValue(__FUNCTION__, #member, pv, cb, uIntraOff, fWrite, false, 0); 280 281 #define LOG_INDEXED_ACCESSOR(member, idx) \ 282 virtioLogMappedIoValue(__FUNCTION__, #member, pv, cb, uIntraOff, fWrite, true, idx); 283 284 #define ACCESSOR(member) \ 275 #define LOG_COMMON_CFG_ACCESS(member) \ 276 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \ 277 pv, cb, uIntraOff, fWrite, false, 0); 278 279 #define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx) \ 280 virtioLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \ 281 pv, cb, uIntraOff, fWrite, true, idx); 282 283 #define COMMON_CFG_ACCESSOR(member) \ 285 284 { \ 286 285 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ … … 289 288 else \ 290 289 memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \ 291 LOG_ ACCESSOR(member); \290 LOG_COMMON_CFG_ACCESS(member); \ 292 291 } 293 292 294 #define ACCESSOR_WITH_IDX(member, idx) \293 #define COMMON_CFG_ACCESSOR_INDEXED(member, idx) \ 295 294 { \ 296 295 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ … … 299 298 else \ 300 299 memcpy((char *)pv, (const char *)(((char *)(pVirtio->member + idx)) + uIntraOff), cb); \ 301 LOG_ INDEXED_ACCESSOR(member, idx); \300 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \ 302 301 } 303 302 304 #define ACCESSOR_READONLY(member) \303 #define COMMON_CFG_ACCESSOR_READONLY(member) \ 305 304 { \ 306 305 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ … … 310 309 { \ 311 310 memcpy((char *)pv, (const char *)(((char *)&pVirtio->member) + uIntraOff), cb); \ 312 LOG_ ACCESSOR(member); \311 LOG_COMMON_CFG_ACCESS(member); \ 313 312 } \ 314 313 } 315 314 316 #define ACCESSOR_READONLY_WITH_IDX(member, idx) \315 #define COMMON_CFG_ACCESSOR_INDEXED_READONLY(member, idx) \ 317 316 { \ 318 317 uint32_t uIntraOff = uOffset - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ … … 321 320 else \ 322 321 { \ 323 memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + u Offset, cb); \324 LOG_ INDEXED_ACCESSOR(member, idx); \322 memcpy((char *)pv, ((char *)(pVirtio->member + idx)) + uIntraOff, cb); \ 323 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx); \ 325 324 } \ 326 325 } 327 326 328 #ifdef VBOX_DEVICE_STRUCT_TESTCASE 329 # define virtioDumpState(x, s) do {} while (0) 330 #else 331 # ifdef DEBUG 332 static void virtioDumpState(PVIRTIOSTATE pVirtio, const char *pcszCaller) 333 { 334 RT_NOREF2(pVirtio, pcszCaller); 335 /* PK TODO, dump state features, selector, status, ISR, queue info (iterate), 336 descriptors, avail, used, size, indices, address 337 each by variable name on new line, indented slightly */ 338 } 339 # endif 340 #endif 341 327 /** 328 * Internal queue operations 329 */ 330 331 static int vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld); 332 static bool vqIsEmpty (PVIRTIOSTATE pVirtio, uint16_t qIdx); 333 static void vqReset (PVIRTIOSTATE pVirtio, uint16_t qIdx); 334 static void vqReadDesc (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc); 335 static uint16_t vqReadAvailRingDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx); 336 static uint16_t vqReadAvailDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx); 337 static uint16_t vqReadAvailFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx); 338 static uint16_t vqReadAvailUsedEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx); 339 static void vqWriteUsedElem (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen); 340 static void vqWriteUsedRingDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uDescIdx); 341 static uint16_t vqReadUsedDescIdx (PVIRTIOSTATE pVirtio, uint16_t qIdx); 342 static uint16_t vqReadUsedFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx); 343 static void vqWriteUsedFlags (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags); 344 static uint16_t vqReadUsedAvailEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx); 345 static void vqWriteUsedAvailEvent (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx); 346 347 DECLINLINE(int) vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld) 348 { 349 return (uint16_t)(uDescIdxNew - uEventIdx - 1) < (uint16_t)(uDescIdxNew - uDescIdxOld); 350 } 351 352 DECLINLINE(bool) vqIsEmpty(PVIRTIOSTATE pVirtio, uint16_t qIdx) 353 { 354 return vqReadAvailDescIdx(pVirtio, qIdx) == pVirtio->queueContext->uNextAvailIdx; 355 } 356 357 /** 358 * Accessor for virtq descspVirtio 359 */ 360 DECLINLINE(void) vqReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc) 361 { 362 //Log(("%s virtioQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQ, idx)); 363 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 364 pVirtio->pGcPhysQueueDesc[qIdx] 365 + sizeof(VIRTQ_DESC_T) * (uDescIdx % pVirtio->uQueueSize[qIdx]), 366 pDesc, sizeof(VIRTQ_DESC_T)); 367 } 368 369 /** 370 * Accessors for virtq avail ring 371 */ 372 DECLINLINE(uint16_t) vqReadAvailRingDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t availIdx) 373 { 374 uint16_t uDescIdx; 375 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 376 pVirtio->pGcPhysQueueAvail[qIdx] 377 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % pVirtio->uQueueSize[qIdx]]), 378 &uDescIdx, sizeof(uDescIdx)); 379 return uDescIdx; 380 } 381 382 DECLINLINE(uint16_t) vqReadAvailDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx) 383 { 384 uint16_t uDescIdx; 385 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 386 pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uDescIdx), 387 &uDescIdx, sizeof(uDescIdx)); 388 return uDescIdx; 389 } 390 391 DECLINLINE(uint16_t) vqReadAvailFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx) 392 { 393 uint16_t fFlags; 394 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 395 pVirtio->pGcPhysQueueAvail[qIdx] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags), 396 &fFlags, sizeof(fFlags)); 397 return fFlags; 398 } 399 400 DECLINLINE(uint16_t) vqReadAvailUsedEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx) 401 { 402 uint16_t uUsedEventIdx; 403 /** VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */ 404 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 405 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uQueueSize[qIdx]]), 406 &uUsedEventIdx, sizeof(uUsedEventIdx)); 407 return uUsedEventIdx; 408 } 409 410 /** 411 * Accessors for virtq used ring 412 */ 413 DECLINLINE(void) vqWriteUsedElem(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen) 414 { 415 VIRTQ_USED_ELEM_T elem = { uDescIdx, uLen }; 416 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 417 pVirtio->pGcPhysQueueUsed[qIdx] 418 + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[usedIdx % pVirtio->uQueueSize[qIdx]]), 419 &elem, sizeof(elem)); 420 } 421 422 DECLINLINE(void) vqWriteUsedRingDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uDescIdx) 423 { 424 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 425 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uDescIdx), 426 &uDescIdx, sizeof(uDescIdx)); 427 } 428 429 DECLINLINE(uint16_t)vqReadUsedDescIdx(PVIRTIOSTATE pVirtio, uint16_t qIdx) 430 { 431 uint16_t uDescIdx; 432 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 433 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, uDescIdx), 434 &uDescIdx, sizeof(uDescIdx)); 435 return uDescIdx; 436 } 437 438 DECLINLINE(uint16_t) vqReadUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx) 439 { 440 uint16_t fFlags; 441 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 442 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags), 443 &fFlags, sizeof(fFlags)); 444 return fFlags; 445 } 446 447 DECLINLINE(void) vqWriteUsedFlags(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t fFlags) 448 { 449 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 450 pVirtio->pGcPhysQueueUsed[qIdx] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags), 451 &fFlags, sizeof(fFlags)); 452 } 453 454 DECLINLINE(uint16_t) vqReadUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx) 455 { 456 uint16_t uAvailEventIdx; 457 /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */ 458 PDMDevHlpPhysRead(pVirtio->CTX_SUFF(pDevIns), 459 + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[pVirtio->uQueueSize[qIdx]]), 460 &uAvailEventIdx, sizeof(uAvailEventIdx)); 461 return uAvailEventIdx; 462 } 463 464 DECLINLINE(void) vqWriteUsedAvailEvent(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uAvailEventIdx) 465 { 466 /** VirtIO 1.0 uAvailEventIdx (avail event) immediately follows ring */ 467 PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns), 468 pVirtio->pGcPhysQueueUsed[qIdx] 469 + RT_UOFFSETOF_DYN(VIRTQ_USED_T, auRing[pVirtio->uQueueSize[qIdx]]), 470 &uAvailEventIdx, sizeof(uAvailEventIdx)); 471 } 472 473 /** 474 * Makes the MMIO-mapped Virtio uDeviceStatus registers non-cryptic */ 342 475 DECLINLINE(void) virtioLogDeviceStatus( uint8_t status) 343 476 { … … 358 491 Log(("%sFAILED", primed++ ? " | " : "")); 359 492 if (status & VIRTIO_STATUS_DEVICE_NEEDS_RESET) 360 Log(("%s ACKNOWLEDGE", primed++ ? " | " : ""));493 Log(("%sNEEDS_RESET", primed++ ? " | " : "")); 361 494 } 362 495 } 363 496 364 /* FROM Virtio 1.0 SPEC, NYI 365 static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx) 366 return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx); 367 } 368 // Get location of event indices (only with VIRTIO_F_EVENT_IDX) 369 static inline le16 *virtq_used_event(struct virtq *vq) 370 { 371 // For backwards compat, used event index is at *end* of avail ring. 372 return &vq->avail->ring[vq->num]; 373 } 374 static inline le16 *virtq_avail_event(struct virtq *vq) 375 { 376 // For backwards compat, avail event index is at *end* of used ring. 377 return (le16 *)&vq->used->ring[vq->num]; 378 } 379 } 380 */ 381 void virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta); 382 void *virtioQueryInterface(struct PDMIBASE *pInterface, const char *pszIID); 383 int virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM); 384 int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t uNumQueues); 497 void vqNotified(PVIRTIOSTATE pVirtio, uint32_t qidx, uint16_t uDescIdx); 498 static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause); 499 500 //void virtioNotifyDriver( VIRTIOHANDLE hVirtio); 501 //void virtQueueNotify( VIRTIOHANDLE hVirtio, PVQUEUE pQueue); 502 //void vringSetNotification( VIRTIOHANDLE hVirtio, PVIRTQ pVirtQ, bool fEnabled); 503 504 static DECLCALLBACK(int) virtioR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); 505 static DECLCALLBACK(int) virtioR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass); 506 static DECLCALLBACK(int) virtioR3LoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM); 507 static DECLCALLBACK(int) virtioR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass); 385 508 386 509 #endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h */
Note:
See TracChangeset
for help on using the changeset viewer.