Changeset 84819 in vbox for trunk/src/VBox/Devices/VirtIO
- Timestamp:
- Jun 12, 2020 8:00:27 PM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 138625
- Location:
- trunk/src/VBox/Devices/VirtIO
- Files:
-
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp
r84818 r84819 1 1 /* $Id$ */ 2 2 3 /** @file 3 * Virtio _1_0 - Virtio Common(PCI, feature & config mgt, queue mgt & proxy, notification mgt)4 * VirtioCore - Virtio Core (PCI, feature & config mgt, queue mgt & proxy, notification mgt) 4 5 */ 5 6 … … 35 36 #include <VBox/AssertGuest.h> 36 37 #include <VBox/vmm/pdmdev.h> 37 #include "Virtio _1_0.h"38 #include "VirtioCore.h" 38 39 39 40 … … 42 43 *********************************************************************************************************************************/ 43 44 #define INSTANCE(a_pVirtio) ((a_pVirtio)->szInstance) 44 #define VIRTQNAME(a_pVirtio, a_ idxVirtq) ((a_pVirtio)->aVirtqState[(a_idxVirtq)].szVirtqName)45 #define VIRTQNAME(a_pVirtio, a_uVirtqNbr) ((a_pVirtio)->aVirtqState[(a_uVirtqNbr)].szVirtqName) 45 46 #define IS_DRIVER_OK(a_pVirtio) ((a_pVirtio)->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 46 47 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtqState) \ … … 135 136 /* Internal Functions */ 136 137 137 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);138 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 138 139 static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec); 139 140 … … 145 146 */ 146 147 #ifdef IN_RING3 147 DECLINLINE(void) virtioReadDesc(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,148 DECLINLINE(void) virtioReadDesc(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 148 149 uint32_t idxDesc, PVIRTQ_DESC_T pDesc) 149 150 { 150 151 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 151 uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[ idxVirtq], 1); /* Make sure to avoid div-by-zero. */152 uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[uVirtqNbr], 1); /* Make sure to avoid div-by-zero. */ 152 153 PDMDevHlpPCIPhysRead(pDevIns, 153 pVirtio->aGCPhysVirtqDesc[ idxVirtq] + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),154 pVirtio->aGCPhysVirtqDesc[uVirtqNbr] + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems), 154 155 pDesc, sizeof(VIRTQ_DESC_T)); 155 156 } … … 160 161 */ 161 162 #ifdef IN_RING3 162 DECLINLINE(uint16_t) virtioReadAvailDescIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint32_t availIdx)163 DECLINLINE(uint16_t) virtioReadAvailDescIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint32_t availIdx) 163 164 { 164 165 uint16_t uDescIdx; 165 166 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 166 uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[ idxVirtq], 1); /* Make sure to avoid div-by-zero. */167 uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[uVirtqNbr], 1); /* Make sure to avoid div-by-zero. */ 167 168 PDMDevHlpPCIPhysRead(pDevIns, 168 pVirtio->aGCPhysVirtqAvail[ idxVirtq]169 pVirtio->aGCPhysVirtqAvail[uVirtqNbr] 169 170 + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % cVirtqItems]), 170 171 &uDescIdx, sizeof(uDescIdx)); … … 172 173 } 173 174 174 DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)175 DECLINLINE(uint16_t) virtioReadAvailUsedEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 175 176 { 176 177 uint16_t uUsedEventIdx; … … 178 179 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 179 180 PDMDevHlpPCIPhysRead(pDevIns, 180 pVirtio->aGCPhysVirtqAvail[ idxVirtq] + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uVirtqSize[idxVirtq]]),181 pVirtio->aGCPhysVirtqAvail[uVirtqNbr] + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtio->uVirtqSize[uVirtqNbr]]), 181 182 &uUsedEventIdx, sizeof(uUsedEventIdx)); 182 183 return uUsedEventIdx; … … 184 185 #endif 185 186 186 DECLINLINE(uint16_t) virtioReadAvailRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)187 DECLINLINE(uint16_t) virtioReadAvailRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 187 188 { 188 189 uint16_t uIdx = 0; 189 190 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 190 191 PDMDevHlpPCIPhysRead(pDevIns, 191 pVirtio->aGCPhysVirtqAvail[ idxVirtq] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),192 pVirtio->aGCPhysVirtqAvail[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx), 192 193 &uIdx, sizeof(uIdx)); 193 194 return uIdx; 194 195 } 195 196 196 DECLINLINE(uint16_t) virtioReadAvailRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)197 DECLINLINE(uint16_t) virtioReadAvailRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 197 198 { 198 199 uint16_t fFlags = 0; 199 200 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 200 201 PDMDevHlpPCIPhysRead(pDevIns, 201 pVirtio->aGCPhysVirtqAvail[ idxVirtq] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),202 pVirtio->aGCPhysVirtqAvail[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags), 202 203 &fFlags, sizeof(fFlags)); 203 204 return fFlags; … … 211 212 212 213 #ifdef IN_RING3 213 DECLINLINE(void) virtioWriteUsedElem(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq,214 DECLINLINE(void) virtioWriteUsedElem(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 214 215 uint32_t usedIdx, uint32_t uDescIdx, uint32_t uLen) 215 216 { 216 217 VIRTQ_USED_ELEM_T elem = { uDescIdx, uLen }; 217 218 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 218 uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[ idxVirtq], 1); /* Make sure to avoid div-by-zero. */219 uint16_t const cVirtqItems = RT_MAX(pVirtio->uVirtqSize[uVirtqNbr], 1); /* Make sure to avoid div-by-zero. */ 219 220 PDMDevHlpPCIPhysWrite(pDevIns, 220 pVirtio->aGCPhysVirtqUsed[ idxVirtq] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cVirtqItems]),221 pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cVirtqItems]), 221 222 &elem, sizeof(elem)); 222 223 } 223 224 224 DECLINLINE(void) virtioWriteUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint16_t fFlags)225 DECLINLINE(void) virtioWriteUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint16_t fFlags) 225 226 { 226 227 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 227 228 RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */ 228 229 PDMDevHlpPCIPhysWrite(pDevIns, 229 pVirtio->aGCPhysVirtqUsed[ idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),230 pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags), 230 231 &fFlags, sizeof(fFlags)); 231 232 } 232 233 #endif 233 234 234 DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint16_t uIdx)235 DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint16_t uIdx) 235 236 { 236 237 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 237 238 PDMDevHlpPCIPhysWrite(pDevIns, 238 pVirtio->aGCPhysVirtqUsed[ idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),239 pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx), 239 240 &uIdx, sizeof(uIdx)); 240 241 } … … 243 244 #ifdef IN_RING3 244 245 245 DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)246 DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 246 247 { 247 248 uint16_t uIdx = 0; 248 249 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 249 250 PDMDevHlpPCIPhysRead(pDevIns, 250 pVirtio->aGCPhysVirtqUsed[ idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),251 pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, uIdx), 251 252 &uIdx, sizeof(uIdx)); 252 253 return uIdx; 253 254 } 254 255 255 DECLINLINE(uint16_t) virtioReadUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)256 DECLINLINE(uint16_t) virtioReadUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 256 257 { 257 258 uint16_t fFlags = 0; 258 259 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 259 260 PDMDevHlpPCIPhysRead(pDevIns, 260 pVirtio->aGCPhysVirtqUsed[ idxVirtq] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),261 pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF(VIRTQ_USED_T, fFlags), 261 262 &fFlags, sizeof(fFlags)); 262 263 return fFlags; 263 264 } 264 265 265 DECLINLINE(void) virtioWriteUsedAvailEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint32_t uAvailEventIdx)266 DECLINLINE(void) virtioWriteUsedAvailEvent(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint32_t uAvailEventIdx) 266 267 { 267 268 /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */ 268 269 AssertMsg(pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n")); 269 270 PDMDevHlpPCIPhysWrite(pDevIns, 270 pVirtio->aGCPhysVirtqUsed[ idxVirtq] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtio->uVirtqSize[idxVirtq]]),271 pVirtio->aGCPhysVirtqUsed[uVirtqNbr] + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtio->uVirtqSize[uVirtqNbr]]), 271 272 &uAvailEventIdx, sizeof(uAvailEventIdx)); 272 273 } … … 277 278 DECLINLINE(uint16_t) virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQSTATE pVirtqState) 278 279 { 279 uint16_t uIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtqState-> idxVirtq);280 uint16_t uIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtqState->uVirtqNbr); 280 281 uint16_t uShadow = pVirtqState->uAvailIdxShadow; 281 282 … … 287 288 288 289 LogFunc(("%s has %u %s (idx=%u shadow=%u)\n", 289 VIRTQNAME(pVirtio, pVirtqState-> idxVirtq), uDelta, uDelta == 1 ? "entry" : "entries",290 VIRTQNAME(pVirtio, pVirtqState->uVirtqNbr), uDelta, uDelta == 1 ? "entry" : "entries", 290 291 uIdx, uShadow)); 291 292 … … 297 298 * @param pDevIns The device instance. 298 299 * @param pVirtio Pointer to the shared virtio state. 299 * @param idxVirtqVirtq number300 * @param uVirtqNbr Virtq number 300 301 * 301 302 * @returns how many entries have been added to ring as a delta of the consumer's 302 303 * avail index and the queue's guest-side current avail index. 303 304 */ 304 uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)305 { 306 if (!IS_DRIVER_OK(pVirtio) || !pVirtio->uVirtqEnable[ idxVirtq])305 uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 306 { 307 if (!IS_DRIVER_OK(pVirtio) || !pVirtio->uVirtqEnable[uVirtqNbr]) 307 308 { 308 309 LogRelFunc(("Driver not ready or queue not enabled\n")); 309 310 return 0; 310 311 } 311 return virtioCoreVirtqAvailCount(pDevIns, pVirtio, &pVirtio->aVirtqState[ idxVirtq]);312 return virtioCoreVirtqAvailCount(pDevIns, pVirtio, &pVirtio->aVirtqState[uVirtqNbr]); 312 313 } 313 314 … … 435 436 436 437 #ifdef IN_RING3 438 439 /** API Function: See header file*/ 437 440 void virtioCorePrintFeatures(VIRTIOCORE *pVirtio, PCDBGFINFOHLP pHlp) 438 441 { … … 478 481 479 482 #ifdef LOG_ENABLED 480 /** 481 * Debug assist for consumer device code. 482 * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to 483 * control enabling of logging efficiently. 484 * 485 * @param pv pointer to buffer to dump contents of 486 * @param cb count of characters to dump from buffer 487 * @param uBase base address of per-row address prefixing of hex output 488 * @param pszTitle Optional title. If present displays title that lists 489 * provided text with value of cb to indicate size next to it. 490 */ 483 484 /** API Function: See header file */ 491 485 void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle) 492 486 { … … 527 521 } 528 522 529 /** 530 * Debug assist for consumer device code. 531 * Do a hex dump of memory in guest physical context 532 * 533 * @param GCPhys pointer to buffer to dump contents of 534 * @param cb count of characters to dump from buffer 535 * @param uBase base address of per-row address prefixing of hex output 536 * @param pszTitle Optional title. If present displays title that lists 537 * provided text with value of cb to indicate size next to it. 538 */ 523 /* API FUnction: See header file */ 539 524 void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle) 540 525 { … … 579 564 #endif /* LOG_ENABLED */ 580 565 581 /** 582 * Log memory-mapped I/O input or output value. 583 * 584 * This is designed to be invoked by macros that can make contextual assumptions 585 * (e.g. implicitly derive MACRO parameters from the invoking function). It is exposed 586 * for the VirtIO client doing the device-specific implementation in order to log in a 587 * similar fashion accesses to the device-specific MMIO configuration structure. Macros 588 * that leverage this function are found in virtioCommonCfgAccessed() and can be 589 * used as an example of how to use this effectively for the device-specific 590 * code. 591 * 592 * @param pszFunc To avoid displaying this function's name via __FUNCTION__ or LogFunc() 593 * @param pszMember Name of struct member 594 * @param pv pointer to value 595 * @param cb size of value 596 * @param uOffset offset into member where value starts 597 * @param fWrite True if write I/O 598 * @param fHasIndex True if the member is indexed 599 * @param idx The index if fHasIndex 600 */ 566 /** API function: See header file */ 601 567 void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize, 602 568 const void *pv, uint32_t cb, uint32_t uOffset, int fWrite, … … 673 639 #ifdef IN_RING3 674 640 675 void virtioCoreR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) 676 { 677 RT_NOREF(pDevIns); 678 bool fNone = pszArgs && *pszArgs == '\0'; 679 bool fAll = pszArgs && (*pszArgs == 'a' || *pszArgs == 'A'); /* "all" */ 680 bool fBasic = pszArgs && (*pszArgs == 'b' || *pszArgs == 'B'); /* "basic" */ 681 bool fState = pszArgs && (*pszArgs == 's' || *pszArgs == 'S'); /* "state" */ 682 bool fPointers = pszArgs && (*pszArgs == 'p' || *pszArgs == 'P'); /* "pointers" */ 683 bool fVirtqs = pszArgs && (*pszArgs == 'q' || *pszArgs == 'Q'); /* "queues */ 684 RT_NOREF6(fNone, fAll, fBasic, fState, fPointers, fVirtqs); 685 pHlp->pfnPrintf(pHlp, ""); 686 687 } 688 689 void virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int idxVirtq) 641 /** API Fuunction: See header file */ 642 void virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int uVirtqNbr) 690 643 { 691 644 RT_NOREF(pszArgs); 692 645 PVIRTIOCORE pVirtio = PDMDEVINS_2_DATA(pDevIns, PVIRTIOCORE); 693 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq]; 694 695 // bool fDump = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)" */ 696 697 uint16_t uAvailIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, idxVirtq); 646 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 647 648 /** @todo add ability to dump physical contents of any descriptor (using existing VirtIO core API function) */ 649 // bool fDump = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)" 650 651 uint16_t uAvailIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, uVirtqNbr); 698 652 uint16_t uAvailIdxShadow = pVirtqState->uAvailIdxShadow; 699 653 700 uint16_t uUsedIdx = virtioReadUsedRingIdx(pDevIns, pVirtio, idxVirtq);654 uint16_t uUsedIdx = virtioReadUsedRingIdx(pDevIns, pVirtio, uVirtqNbr); 701 655 uint16_t uUsedIdxShadow = pVirtqState->uUsedIdxShadow; 702 656 703 PVIRT IO_DESC_CHAIN_T pDescChain= NULL;657 PVIRTQBUF pVirtqBuf = NULL; 704 658 705 659 bool fEmpty = IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtqState); 706 660 707 LogFunc(("%s, empty = %s\n", VIRTQNAME(pVirtio, idxVirtq), fEmpty ? "true" : "false"));661 LogFunc(("%s, empty = %s\n", VIRTQNAME(pVirtio, uVirtqNbr), fEmpty ? "true" : "false")); 708 662 709 663 int cSendSegs = 0, cReturnSegs = 0; 710 664 if (!fEmpty) 711 665 { 712 virtioCoreR3Virtq Peek(pDevIns, pVirtio, idxVirtq, &pDescChain);713 cSendSegs = p DescChain->pSgPhysSend ? pDescChain->pSgPhysSend->cSegs : 0;714 cReturnSegs = p DescChain->pSgPhysReturn ? pDescChain->pSgPhysReturn->cSegs : 0;715 } 716 717 bool fAvailNoInterrupt = virtioReadAvailRingFlags(pDevIns, pVirtio, idxVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT;718 bool fUsedNoNotify = virtioReadUsedRingFlags(pDevIns, pVirtio, idxVirtq) & VIRTQ_USED_F_NO_NOTIFY;719 720 721 pHlp->pfnPrintf(pHlp, " queue enabled: ........... %s\n", pVirtio->uVirtqEnable[ idxVirtq] ? "true" : "false");722 pHlp->pfnPrintf(pHlp, " size: .................... %d\n", pVirtio->uVirtqSize[ idxVirtq]);723 pHlp->pfnPrintf(pHlp, " notify offset: ........... %d\n", pVirtio->uVirtqNotifyOff[ idxVirtq]);666 virtioCoreR3VirtqBufPeek(pDevIns, pVirtio, uVirtqNbr, &pVirtqBuf); 667 cSendSegs = pVirtqBuf->pSgPhysSend ? pVirtqBuf->pSgPhysSend->cSegs : 0; 668 cReturnSegs = pVirtqBuf->pSgPhysReturn ? pVirtqBuf->pSgPhysReturn->cSegs : 0; 669 } 670 671 bool fAvailNoInterrupt = virtioReadAvailRingFlags(pDevIns, pVirtio, uVirtqNbr) & VIRTQ_AVAIL_F_NO_INTERRUPT; 672 bool fUsedNoNotify = virtioReadUsedRingFlags(pDevIns, pVirtio, uVirtqNbr) & VIRTQ_USED_F_NO_NOTIFY; 673 674 675 pHlp->pfnPrintf(pHlp, " queue enabled: ........... %s\n", pVirtio->uVirtqEnable[uVirtqNbr] ? "true" : "false"); 676 pHlp->pfnPrintf(pHlp, " size: .................... %d\n", pVirtio->uVirtqSize[uVirtqNbr]); 677 pHlp->pfnPrintf(pHlp, " notify offset: ........... %d\n", pVirtio->uVirtqNotifyOff[uVirtqNbr]); 724 678 if (pVirtio->fMsiSupport) 725 pHlp->pfnPrintf(pHlp, " MSIX vector: ....... %4.4x\n", pVirtio->uVirtqMsixVector[ idxVirtq]);679 pHlp->pfnPrintf(pHlp, " MSIX vector: ....... %4.4x\n", pVirtio->uVirtqMsixVector[uVirtqNbr]); 726 680 pHlp->pfnPrintf(pHlp, "\n"); 727 681 pHlp->pfnPrintf(pHlp, " avail ring (%d entries):\n", uAvailIdx - uAvailIdxShadow); … … 740 694 pHlp->pfnPrintf(pHlp, " head idx: ............. %d\n", uUsedIdx); 741 695 pHlp->pfnPrintf(pHlp, " segs: ................. %d\n", cSendSegs + cReturnSegs); 742 pHlp->pfnPrintf(pHlp, " refCnt ................ %d\n", p DescChain->cRefs);696 pHlp->pfnPrintf(pHlp, " refCnt ................ %d\n", pVirtqBuf->cRefs); 743 697 pHlp->pfnPrintf(pHlp, "\n"); 744 pHlp->pfnPrintf(pHlp, " host-to-guest (%d bytes):\n", p DescChain->cbPhysSend);698 pHlp->pfnPrintf(pHlp, " host-to-guest (%d bytes):\n", pVirtqBuf->cbPhysSend); 745 699 pHlp->pfnPrintf(pHlp, " segs: .............. %d\n", cSendSegs); 746 700 if (cSendSegs) 747 701 { 748 pHlp->pfnPrintf(pHlp, " index: ............. %d\n", p DescChain->pSgPhysSend->idxSeg);749 pHlp->pfnPrintf(pHlp, " unsent ............. %d\n", p DescChain->pSgPhysSend->cbSegLeft);702 pHlp->pfnPrintf(pHlp, " index: ............. %d\n", pVirtqBuf->pSgPhysSend->idxSeg); 703 pHlp->pfnPrintf(pHlp, " unsent ............. %d\n", pVirtqBuf->pSgPhysSend->cbSegLeft); 750 704 } 751 705 pHlp->pfnPrintf(pHlp, "\n"); 752 pHlp->pfnPrintf(pHlp, " guest-to-host (%d bytes)\n", p DescChain->cbPhysReturn);706 pHlp->pfnPrintf(pHlp, " guest-to-host (%d bytes)\n", pVirtqBuf->cbPhysReturn); 753 707 pHlp->pfnPrintf(pHlp, " segs: .............. %d\n", cReturnSegs); 754 708 if (cReturnSegs) 755 709 { 756 pHlp->pfnPrintf(pHlp, " index: ............. %d\n", p DescChain->pSgPhysReturn->idxSeg);757 pHlp->pfnPrintf(pHlp, " unsent ............. %d\n", p DescChain->pSgPhysReturn->cbSegLeft);710 pHlp->pfnPrintf(pHlp, " index: ............. %d\n", pVirtqBuf->pSgPhysReturn->idxSeg); 711 pHlp->pfnPrintf(pHlp, " unsent ............. %d\n", pVirtqBuf->pSgPhysReturn->cbSegLeft); 758 712 } 759 713 } else … … 763 717 } 764 718 765 /** 766 * Allocate client context for client to work with VirtIO-#provided with queue 767 * 768 * @param pVirtio Pointer to the shared virtio state. 769 * @param idxVirtq Virtq number 770 * @param pcszName Name to give queue 771 * 772 * @returns VBox status code. 773 */ 774 int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t idxVirtq, const char *pcszName) 719 int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, const char *pcszName) 775 720 { 776 721 LogFunc(("%s\n", pcszName)); 777 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[ idxVirtq];778 pVirtqState-> idxVirtq = idxVirtq;722 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 723 pVirtqState->uVirtqNbr = uVirtqNbr; 779 724 pVirtqState->uAvailIdxShadow = 0; 780 725 pVirtqState->uUsedIdxShadow = 0; … … 788 733 #ifdef IN_RING3 789 734 790 int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, 791 uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain) 792 { 793 AssertReturn(ppDescChain, VERR_INVALID_POINTER); 794 *ppDescChain = NULL; 795 796 Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState)); 797 798 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq]; 799 800 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[idxVirtq], 735 /** API Function: See header file */ 736 int virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 737 uint16_t uHeadIdx, PPVIRTQBUF ppVirtqBuf) 738 { 739 AssertReturn(ppVirtqBuf, VERR_INVALID_POINTER); 740 *ppVirtqBuf = NULL; 741 742 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 743 744 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 745 746 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[uVirtqNbr], 801 747 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 802 748 … … 809 755 * Allocate and initialize the descriptor chain structure. 810 756 */ 811 PVIRT IO_DESC_CHAIN_T pDescChain = (PVIRTIO_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTIO_DESC_CHAIN_T));812 AssertReturn(p DescChain, VERR_NO_MEMORY);813 p DescChain->u32Magic = VIRTIO_DESC_CHAIN_MAGIC;814 p DescChain->cRefs = 1;815 p DescChain->uHeadIdx = uHeadIdx;816 *pp DescChain = pDescChain;757 PVIRTQBUF pVirtqBuf = (PVIRTQBUF)RTMemAllocZ(sizeof(VIRTQBUF_T)); 758 AssertReturn(pVirtqBuf, VERR_NO_MEMORY); 759 pVirtqBuf->u32Magic = VIRTQBUF_MAGIC; 760 pVirtqBuf->cRefs = 1; 761 pVirtqBuf->uHeadIdx = uHeadIdx; 762 *ppVirtqBuf = pVirtqBuf; 817 763 818 764 /* … … 825 771 uint32_t cSegsIn = 0; 826 772 uint32_t cSegsOut = 0; 827 PVIRTIOSGSEG paSegsIn = p DescChain->aSegsIn;828 PVIRTIOSGSEG paSegsOut = p DescChain->aSegsOut;773 PVIRTIOSGSEG paSegsIn = pVirtqBuf->aSegsIn; 774 PVIRTIOSGSEG paSegsOut = pVirtqBuf->aSegsOut; 829 775 830 776 do … … 853 799 RT_UNTRUSTED_VALIDATED_FENCE(); 854 800 855 virtioReadDesc(pDevIns, pVirtio, idxVirtq, uDescIdx, &desc);801 virtioReadDesc(pDevIns, pVirtio, uVirtqNbr, uDescIdx, &desc); 856 802 857 803 if (desc.fFlags & VIRTQ_DESC_F_WRITE) 858 804 { 859 Log6Func(("%s IN desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, idxVirtq), uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));805 Log6Func(("%s IN desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, uVirtqNbr), uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb)); 860 806 cbIn += desc.cb; 861 807 pSeg = &paSegsIn[cSegsIn++]; … … 863 809 else 864 810 { 865 Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, idxVirtq), uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));811 Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", VIRTQNAME(pVirtio, uVirtqNbr), uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb)); 866 812 cbOut += desc.cb; 867 813 pSeg = &paSegsOut[cSegsOut++]; … … 884 830 if (cSegsIn) 885 831 { 886 virtioCoreSgBufInit(&p DescChain->SgBufIn, paSegsIn, cSegsIn);887 p DescChain->pSgPhysReturn = &pDescChain->SgBufIn;888 p DescChain->cbPhysReturn = cbIn;832 virtioCoreSgBufInit(&pVirtqBuf->SgBufIn, paSegsIn, cSegsIn); 833 pVirtqBuf->pSgPhysReturn = &pVirtqBuf->SgBufIn; 834 pVirtqBuf->cbPhysReturn = cbIn; 889 835 STAM_REL_COUNTER_ADD(&pVirtio->StatDescChainsSegsIn, cSegsIn); 890 836 } … … 892 838 if (cSegsOut) 893 839 { 894 virtioCoreSgBufInit(&p DescChain->SgBufOut, paSegsOut, cSegsOut);895 p DescChain->pSgPhysSend = &pDescChain->SgBufOut;896 p DescChain->cbPhysSend = cbOut;840 virtioCoreSgBufInit(&pVirtqBuf->SgBufOut, paSegsOut, cSegsOut); 841 pVirtqBuf->pSgPhysSend = &pVirtqBuf->SgBufOut; 842 pVirtqBuf->cbPhysSend = cbOut; 897 843 STAM_REL_COUNTER_ADD(&pVirtio->StatDescChainsSegsOut, cSegsOut); 898 844 } … … 904 850 } 905 851 906 907 /** 908 * Retains a reference to the given descriptor chain. 909 * 910 * @returns New reference count. 911 * @retval UINT32_MAX on invalid parameter. 912 * @param pDescChain The descriptor chain to reference. 913 */ 914 uint32_t virtioCoreR3DescChainRetain(PVIRTIO_DESC_CHAIN_T pDescChain) 915 { 916 AssertReturn(pDescChain, UINT32_MAX); 917 AssertReturn(pDescChain->u32Magic == VIRTIO_DESC_CHAIN_MAGIC, UINT32_MAX); 918 uint32_t cRefs = ASMAtomicIncU32(&pDescChain->cRefs); 852 /** API Function: See header file */ 853 uint32_t virtioCoreR3VirtqBufRetain(PVIRTQBUF pVirtqBuf) 854 { 855 AssertReturn(pVirtqBuf, UINT32_MAX); 856 AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, UINT32_MAX); 857 uint32_t cRefs = ASMAtomicIncU32(&pVirtqBuf->cRefs); 919 858 Assert(cRefs > 1); 920 859 Assert(cRefs < 16); … … 923 862 924 863 925 /** 926 * Releases a reference to the given descriptor chain. 927 * 928 * @returns New reference count. 929 * @retval 0 if freed or invalid parameter. 930 * @param pVirtio Pointer to the shared virtio state. 931 * @param pDescChain The descriptor chain to reference. NULL is quietly 932 * ignored (returns 0). 933 */ 934 uint32_t virtioCoreR3DescChainRelease(PVIRTIOCORE pVirtio, PVIRTIO_DESC_CHAIN_T pDescChain) 935 { 936 if (!pDescChain) 864 /** API Function: See header file */ 865 uint32_t virtioCoreR3VirtqBufRelease(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf) 866 { 867 if (!pVirtqBuf) 937 868 return 0; 938 AssertReturn(p DescChain, 0);939 AssertReturn(p DescChain->u32Magic == VIRTIO_DESC_CHAIN_MAGIC, 0);940 uint32_t cRefs = ASMAtomicDecU32(&p DescChain->cRefs);869 AssertReturn(pVirtqBuf, 0); 870 AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, 0); 871 uint32_t cRefs = ASMAtomicDecU32(&pVirtqBuf->cRefs); 941 872 Assert(cRefs < 16); 942 873 if (cRefs == 0) 943 874 { 944 p DescChain->u32Magic = ~VIRTIO_DESC_CHAIN_MAGIC;945 RTMemFree(p DescChain);875 pVirtqBuf->u32Magic = ~VIRTQBUF_MAGIC; 876 RTMemFree(pVirtqBuf); 946 877 STAM_REL_COUNTER_INC(&pVirtio->StatDescChainsFreed); 947 878 } … … 949 880 } 950 881 951 952 /* 953 * Notifies guest (via ISR or MSI-X) of device configuration change 954 * 955 * @param pVirtio Pointer to the shared virtio state. 956 */ 882 /** API Function: See header file */ 957 883 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio) 958 884 { … … 960 886 } 961 887 962 /** 963 * Enable or Disable notification for the specified queue 964 * 965 * @param pVirtio Pointer to the shared virtio state. 966 * @param idxVirtq Virtq number 967 * @param fEnable Selects notification mode (enabled or disabled) 968 */ 969 void virtioCoreVirtqNotifyEnable(PVIRTIOCORE pVirtio, uint16_t idxVirtq, bool fEnable) 888 void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable) 970 889 { 971 890 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 972 891 { 973 uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, idxVirtq);892 uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, uVirtqNbr); 974 893 975 894 if (fEnable) … … 978 897 fFlags |= VIRTQ_USED_F_NO_NOTIFY; 979 898 980 virtioWriteUsedRingFlags(pVirtio->pDevInsR3, pVirtio, idxVirtq, fFlags); 981 } 982 } 983 984 /** 985 * Initiate orderly reset procedure. This is an exposed API for clients that might need it. 986 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2) 987 * 988 * @param pVirtio Pointer to the virtio state. 989 */ 899 virtioWriteUsedRingFlags(pVirtio->pDevInsR3, pVirtio, uVirtqNbr, fFlags); 900 } 901 } 902 903 /** API function: See Header file */ 990 904 void virtioCoreResetAll(PVIRTIOCORE pVirtio) 991 905 { … … 999 913 } 1000 914 1001 /** 1002 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor 1003 * chain into its OUT (to device) and IN to guest components, but does NOT remove it from 1004 * the 'avail' queue. I.e. doesn't advance the index. This can be used with virtioVirtqSkip(), 1005 * which *does* advance the avail index. Together they facilitate a mechanism that allows 1006 * work with a queue element (descriptor chain) to be aborted if necessary, by not advancing 1007 * the pointer, or, upon success calling the skip function (above) to move to the next element. 1008 * 1009 * Additionally it converts the OUT desc chain data to a contiguous virtual 1010 * memory buffer for easy consumption by the caller. The caller must return the 1011 * descriptor chain pointer via virtioCoreR3VirtqPut() and then call virtioCoreVirtqSync() 1012 * at some point to return the data to the guest and complete the transaction. 1013 * 1014 * @param pDevIns The device instance. 1015 * @param pVirtio Pointer to the shared virtio state. 1016 * @param idxVirtq Virtq number 1017 * @param ppDescChain Address to store pointer to descriptor chain that contains the 1018 * pre-processed transaction information pulled from the virtq. 1019 * 1020 * @returns VBox status code: 1021 * @retval VINF_SUCCESS Success 1022 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted). 1023 * @retval VERR_NOT_AVAILABLE If the queue is empty. 1024 */ 1025 1026 int virtioCoreR3VirtqPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, 1027 PPVIRTIO_DESC_CHAIN_T ppDescChain) 1028 { 1029 return virtioCoreR3VirtqGet(pDevIns, pVirtio, idxVirtq, ppDescChain, false); 1030 } 1031 1032 /** 1033 * Skip the next entry in the specified queue (typically used with virtioCoreR3VirtqPeek()) 1034 * 1035 * @param pVirtio Pointer to the virtio state. 1036 * @param idxVirtq Index of queue 1037 */ 1038 int virtioCoreR3VirtqSkip(PVIRTIOCORE pVirtio, uint16_t idxVirtq) 1039 { 1040 Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState)); 1041 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq]; 1042 1043 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[idxVirtq], 915 /** API function: See Header file */ 916 int virtioCoreR3VirtqBufPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 917 PPVIRTQBUF ppVirtqBuf) 918 { 919 return virtioCoreR3VirtqBufGet(pDevIns, pVirtio, uVirtqNbr, ppVirtqBuf, false); 920 } 921 922 /** API function: See Header file */ 923 int virtioCoreR3VirtqBufSkip(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 924 { 925 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 926 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 927 928 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[uVirtqNbr], 1044 929 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 1045 930 … … 1053 938 } 1054 939 1055 /** 1056 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor 1057 * chain into its OUT (to device) and IN to guest components. 1058 * 1059 * Additionally it converts the OUT desc chain data to a contiguous virtual 1060 * memory buffer for easy consumption by the caller. The caller must return the 1061 * descriptor chain pointer via virtioCoreR3VirtqPut() and then call virtioCoreVirtqSync() 1062 * at some point to return the data to the guest and complete the transaction. 1063 * 1064 * @param pDevIns The device instance. 1065 * @param pVirtio Pointer to the shared virtio state. 1066 * @param idxVirtq Virtq number 1067 * @param ppDescChain Address to store pointer to descriptor chain that contains the 1068 * pre-processed transaction information pulled from the virtq. 1069 * Returned reference must be released by calling 1070 * virtioCoreR3DescChainRelease(). 1071 * @param fRemove flags whether to remove desc chain from queue (false = peek) 1072 * 1073 * @returns VBox status code: 1074 * @retval VINF_SUCCESS Success 1075 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted). 1076 * @retval VERR_NOT_AVAILABLE If the queue is empty. 1077 */ 1078 int virtioCoreR3VirtqGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, 1079 PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove) 1080 { 1081 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq]; 940 /** API function: See Header file */ 941 int virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 942 PPVIRTQBUF ppVirtqBuf, bool fRemove) 943 { 944 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 1082 945 1083 946 if (IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtqState)) 1084 947 return VERR_NOT_AVAILABLE; 1085 948 1086 uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, idxVirtq, pVirtqState->uAvailIdxShadow);949 uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, uVirtqNbr, pVirtqState->uAvailIdxShadow); 1087 950 1088 951 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 1089 virtioWriteUsedAvailEvent(pDevIns,pVirtio, idxVirtq, pVirtqState->uAvailIdxShadow + 1);952 virtioWriteUsedAvailEvent(pDevIns,pVirtio, uVirtqNbr, pVirtqState->uAvailIdxShadow + 1); 1090 953 1091 954 if (fRemove) 1092 955 pVirtqState->uAvailIdxShadow++; 1093 956 1094 int rc = virtioCoreR3 DescChainGet(pDevIns, pVirtio, idxVirtq, uHeadIdx, ppDescChain);957 int rc = virtioCoreR3VirtqBufGet(pDevIns, pVirtio, uVirtqNbr, uHeadIdx, ppVirtqBuf); 1095 958 return rc; 1096 959 } 1097 960 1098 /** 1099 * Returns data to the guest to complete a transaction initiated by virtVirtqGet(). 1100 * 1101 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments 1102 * and a pointer to the descriptor chain context originally derived from the pulled 1103 * queue entry, and this function will write the virtual memory s/g buffer into the 1104 * guest's physical memory free the descriptor chain. The caller handles the freeing 1105 * (as needed) of the virtual memory buffer. 1106 * 1107 * @note This does a write-ahead to the used ring of the guest's queue. The data 1108 * written won't be seen by the guest until the next call to virtioCoreVirtqSync() 1109 * 1110 * 1111 * @param pDevIns The device instance (for reading). 1112 * @param pVirtio Pointer to the shared virtio state. 1113 * @param idxVirtq Virtq number 1114 * 1115 * @param pSgVirtReturn Points to scatter-gather buffer of virtual memory 1116 * segments the caller is returning to the guest. 1117 * 1118 * @param pDescChain This contains the context of the scatter-gather 1119 * buffer originally pulled from the queue. 1120 * 1121 * @param fFence If true, put up copy fence (memory barrier) after 1122 * copying to guest phys. mem. 1123 * 1124 * @returns VBox status code. 1125 * @retval VINF_SUCCESS Success 1126 * @retval VERR_INVALID_STATE VirtIO not in ready state 1127 * @retval VERR_NOT_AVAILABLE Virtq is empty 1128 * 1129 * @note This function will not release any reference to pDescChain. The 1130 * caller must take care of that. 1131 */ 1132 int virtioCoreR3VirtqPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, PRTSGBUF pSgVirtReturn, 1133 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence) 1134 { 1135 Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState)); 1136 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq]; 1137 PVIRTIOSGBUF pSgPhysReturn = pDescChain->pSgPhysReturn; 1138 1139 Assert(pDescChain->u32Magic == VIRTIO_DESC_CHAIN_MAGIC); 1140 Assert(pDescChain->cRefs > 0); 961 /** API function: See Header file */ 962 int virtioCoreR3VirtqBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, PRTSGBUF pSgVirtReturn, 963 PVIRTQBUF pVirtqBuf, bool fFence) 964 { 965 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 966 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 967 PVIRTIOSGBUF pSgPhysReturn = pVirtqBuf->pSgPhysReturn; 968 969 Assert(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC); 970 Assert(pVirtqBuf->cRefs > 0); 1141 971 1142 972 AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 1143 973 1144 974 Log6Func(("Copying client data to %s, desc chain (head desc_idx %d)\n", 1145 VIRTQNAME(pVirtio, idxVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, idxVirtq)));975 VIRTQNAME(pVirtio, uVirtqNbr), virtioReadUsedRingIdx(pDevIns, pVirtio, uVirtqNbr))); 1146 976 1147 977 /* Copy s/g buf (virtual memory) to guest phys mem (IN direction). */ … … 1173 1003 /* If this write-ahead crosses threshold where the driver wants to get an event flag it */ 1174 1004 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 1175 if (pVirtqState->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxVirtq))1005 if (pVirtqState->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, uVirtqNbr)) 1176 1006 pVirtqState->fVirtqRingEventThreshold = true; 1177 1007 … … 1179 1009 * Place used buffer's descriptor in used ring but don't update used ring's slot index. 1180 1010 * That will be done with a subsequent client call to virtioCoreVirtqSync() */ 1181 virtioWriteUsedElem(pDevIns, pVirtio, idxVirtq, pVirtqState->uUsedIdxShadow++, pDescChain->uHeadIdx, (uint32_t)cbTotal);1011 virtioWriteUsedElem(pDevIns, pVirtio, uVirtqNbr, pVirtqState->uUsedIdxShadow++, pVirtqBuf->uHeadIdx, (uint32_t)cbTotal); 1182 1012 1183 1013 if (pSgVirtReturn) 1184 1014 Log6Func((".... Copied %zu bytes in %d segs to %u byte buffer, residual=%zu\n", 1185 cbTotal - cbRemain, pSgVirtReturn->cSegs, p DescChain->cbPhysReturn, pDescChain->cbPhysReturn - cbTotal));1015 cbTotal - cbRemain, pSgVirtReturn->cSegs, pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal)); 1186 1016 1187 1017 Log6Func(("Write ahead used_idx=%u, %s used_idx=%u\n", 1188 pVirtqState->uUsedIdxShadow, VIRTQNAME(pVirtio, idxVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, idxVirtq)));1018 pVirtqState->uUsedIdxShadow, VIRTQNAME(pVirtio, uVirtqNbr), virtioReadUsedRingIdx(pDevIns, pVirtio, uVirtqNbr))); 1189 1019 1190 1020 return VINF_SUCCESS; … … 1193 1023 #endif /* IN_RING3 */ 1194 1024 1025 /** API function: See Header file */ 1026 int virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 1027 { 1028 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 1029 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 1030 1031 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[uVirtqNbr], 1032 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 1033 1034 Log6Func(("Updating %s used_idx to %u\n", 1035 VIRTQNAME(pVirtio, uVirtqNbr), pVirtqState->uUsedIdxShadow)); 1036 1037 virtioWriteUsedRingIdx(pDevIns, pVirtio, uVirtqNbr, pVirtqState->uUsedIdxShadow); 1038 virtioCoreNotifyGuestDriver(pDevIns, pVirtio, uVirtqNbr); 1039 1040 return VINF_SUCCESS; 1041 } 1042 1043 1195 1044 /** 1196 * Updates the indicated virtq's "used ring" descriptor index to match the 1197 * current write-head index, thus exposing the data added to the used ring by all 1198 * virtioCoreR3VirtqPut() calls since the last sync. This should be called after one or 1199 * more virtioCoreR3VirtqPut() calls to inform the guest driver there is data in the queue. 1200 * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest, 1201 * depending on VirtIO features negotiated and conditions, otherwise the guest 1202 * will detect the update by polling. (see VirtIO 1.0 specification, Section 2.4 "Virtqueues"). 1203 * 1204 * @param pDevIns The device instance. 1205 * @param pVirtio Pointer to the shared virtio state. 1206 * @param idxVirtq Virtq number 1207 * 1208 * @returns VBox status code. 1209 * @retval VINF_SUCCESS Success 1210 * @retval VERR_INVALID_STATE VirtIO not in ready state 1211 */ 1212 int virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq) 1213 { 1214 Assert(idxVirtq < RT_ELEMENTS(pVirtio->aVirtqState)); 1215 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[idxVirtq]; 1216 1217 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uVirtqEnable[idxVirtq], 1218 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 1219 1220 Log6Func(("Updating %s used_idx to %u\n", 1221 VIRTQNAME(pVirtio, idxVirtq), pVirtqState->uUsedIdxShadow)); 1222 1223 virtioWriteUsedRingIdx(pDevIns, pVirtio, idxVirtq, pVirtqState->uUsedIdxShadow); 1224 virtioCoreNotifyGuestDriver(pDevIns, pVirtio, idxVirtq); 1225 1226 return VINF_SUCCESS; 1227 } 1228 1229 1230 /** 1231 */ 1232 static void virtioCoreVirtqNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, uint16_t uNotifyIdx) 1045 */ 1046 static void virtioCoreVirtqNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, uint16_t uNotifyIdx) 1233 1047 { 1234 1048 1235 1049 PVIRTIOCORECC pVirtioCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIOCORECC); 1236 1050 1237 /* See VirtIO 1.0, section 4.1.5.2 It implies that idxVirtqand uNotifyIdx should match.1051 /* See VirtIO 1.0, section 4.1.5.2 It implies that uVirtqNbr and uNotifyIdx should match. 1238 1052 * Disregarding this notification may cause throughput to stop, however there's no way to know 1239 1053 * which was queue was intended for wake-up if the two parameters disagree. */ 1240 1054 1241 AssertMsg(uNotifyIdx == idxVirtq,1055 AssertMsg(uNotifyIdx == uVirtqNbr, 1242 1056 ("Guest kicked virtq %d's notify addr w/non-corresponding virtq idx %d\n", 1243 idxVirtq, uNotifyIdx));1057 uVirtqNbr, uNotifyIdx)); 1244 1058 RT_NOREF(uNotifyIdx); 1245 1059 1246 AssertReturnVoid( idxVirtq< RT_ELEMENTS(pVirtio->aVirtqState));1060 AssertReturnVoid(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 1247 1061 Log6Func(("%s (desc chains: %u)\n", 1248 pVirtio->aVirtqState[ idxVirtq].szVirtqName,1249 virtioCoreVirtqAvailCount(pDevIns, pVirtio, idxVirtq)));1062 pVirtio->aVirtqState[uVirtqNbr].szVirtqName, 1063 virtioCoreVirtqAvailCount(pDevIns, pVirtio, uVirtqNbr))); 1250 1064 1251 1065 /* Inform client */ 1252 pVirtioCC->pfnVirtqNotified(pDevIns, pVirtio, idxVirtq);1066 pVirtioCC->pfnVirtqNotified(pDevIns, pVirtio, uVirtqNbr); 1253 1067 } 1254 1068 … … 1262 1076 * @param pDevIns The device instance. 1263 1077 * @param pVirtio Pointer to the shared virtio state. 1264 * @param idxVirtqVirtq to check for guest interrupt handling preference1265 */ 1266 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq)1267 { 1268 1269 Assert( idxVirtq< RT_ELEMENTS(pVirtio->aVirtqState));1270 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[ idxVirtq];1078 * @param uVirtqNbr Virtq to check for guest interrupt handling preference 1079 */ 1080 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 1081 { 1082 1083 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 1084 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 1271 1085 1272 1086 if (!IS_DRIVER_OK(pVirtio)) … … 1282 1096 #ifdef IN_RING3 1283 1097 Log6Func(("...kicking guest %s, VIRTIO_F_EVENT_IDX set and threshold (%d) reached\n", 1284 VIRTQNAME(pVirtio, idxVirtq), (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, idxVirtq)));1098 VIRTQNAME(pVirtio, uVirtqNbr), (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, uVirtqNbr))); 1285 1099 #endif 1286 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[ idxVirtq]);1100 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[uVirtqNbr]); 1287 1101 pVirtqState->fVirtqRingEventThreshold = false; 1288 1102 return; … … 1290 1104 #ifdef IN_RING3 1291 1105 Log6Func(("...skip interrupt %s, VIRTIO_F_EVENT_IDX set but threshold (%d) not reached (%d)\n", 1292 VIRTQNAME(pVirtio, idxVirtq),(uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, idxVirtq), pVirtqState->uUsedIdxShadow));1106 VIRTQNAME(pVirtio, uVirtqNbr),(uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, uVirtqNbr), pVirtqState->uUsedIdxShadow)); 1293 1107 #endif 1294 1108 } … … 1296 1110 { 1297 1111 /** If guest driver hasn't suppressed interrupts, interrupt */ 1298 if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, idxVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT))1299 { 1300 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[ idxVirtq]);1112 if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, uVirtqNbr) & VIRTQ_AVAIL_F_NO_INTERRUPT)) 1113 { 1114 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uVirtqMsixVector[uVirtqNbr]); 1301 1115 return; 1302 1116 } 1303 1117 Log6Func(("...skipping interrupt for %s (guest set VIRTQ_AVAIL_F_NO_INTERRUPT)\n", 1304 VIRTQNAME(pVirtio, idxVirtq)));1118 VIRTQNAME(pVirtio, uVirtqNbr))); 1305 1119 } 1306 1120 } … … 1347 1161 1348 1162 #ifdef IN_RING3 1349 static void virtioResetVirtq(PVIRTIOCORE pVirtio, uint16_t idxVirtq)1350 { 1351 Assert( idxVirtq< RT_ELEMENTS(pVirtio->aVirtqState));1352 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[ idxVirtq];1163 static void virtioResetVirtq(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 1164 { 1165 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 1166 PVIRTQSTATE pVirtqState = &pVirtio->aVirtqState[uVirtqNbr]; 1353 1167 pVirtqState->uAvailIdxShadow = 0; 1354 1168 pVirtqState->uUsedIdxShadow = 0; 1355 1169 pVirtqState->fVirtqRingEventThreshold = false; 1356 pVirtio->uVirtqEnable[ idxVirtq] = false;1357 pVirtio->uVirtqSize[ idxVirtq] = VIRTQ_MAX_ENTRIES;1358 pVirtio->uVirtqNotifyOff[ idxVirtq] = idxVirtq;1359 pVirtio->uVirtqMsixVector[ idxVirtq] = idxVirtq+ 2;1170 pVirtio->uVirtqEnable[uVirtqNbr] = false; 1171 pVirtio->uVirtqSize[uVirtqNbr] = VIRTQ_MAX_ENTRIES; 1172 pVirtio->uVirtqNotifyOff[uVirtqNbr] = uVirtqNbr; 1173 pVirtio->uVirtqMsixVector[uVirtqNbr] = uVirtqNbr + 2; 1360 1174 if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */ 1361 pVirtio->uVirtqMsixVector[ idxVirtq] = VIRTIO_MSI_NO_VECTOR;1362 1363 virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtio->uVirtqMsixVector[ idxVirtq]);1175 pVirtio->uVirtqMsixVector[uVirtqNbr] = VIRTIO_MSI_NO_VECTOR; 1176 1177 virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtio->uVirtqMsixVector[uVirtqNbr]); 1364 1178 } 1365 1179 … … 1388 1202 pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR; 1389 1203 1390 for (uint16_t idxVirtq = 0; idxVirtq < VIRTQ_MAX_CNT; idxVirtq++)1391 virtioResetVirtq(pVirtio, idxVirtq);1204 for (uint16_t uVirtqNbr = 0; uVirtqNbr < VIRTQ_MAX_CNT; uVirtqNbr++) 1205 virtioResetVirtq(pVirtio, uVirtqNbr); 1392 1206 } 1393 1207 … … 2026 1840 break; 2027 1841 case kvirtIoVmStateChangedResume: 2028 virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* idxVirtq*/);1842 virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* uVirtqNbr */); 2029 1843 break; 2030 1844 default: -
trunk/src/VBox/Devices/VirtIO/VirtioCore.h
r84818 r84819 1 1 /* $Id$ */ 2 2 3 /** @file 3 * Virtio _1_0.h - Virtio Declarations4 * VirtioCore.h - Virtio Declarations 4 5 */ 5 6 … … 93 94 94 95 /** 95 * Virtio descriptor chain representation. 96 */ 97 typedef struct VIRTIO_DESC_CHAIN 98 { 99 uint32_t u32Magic; /**< Magic value, VIRTIO_DESC_CHAIN_MAGIC. */ 96 * VirtIO buffers are actually descriptor chains. VirtIO's scatter-gather architecture 97 * defines a head descriptor (index into ring of descriptors), which is chained to 0 or more 98 * other descriptors that can optionally continue the chain. This structure is VirtualBox's 99 * Virtq buffer representation, which contains a reference to the head desc chain idx and 100 * context for working with virtq buffers. 101 */ 102 typedef struct VIRTQBUF 103 { 104 uint32_t u32Magic; /**< Magic value, VIRTQBUF_MAGIC. */ 100 105 uint32_t volatile cRefs; /**< Reference counter. */ 101 106 uint32_t uHeadIdx; /**< Head idx of associated desc chain */ … … 112 117 VIRTIOSGSEG aSegsOut[VIRTQ_MAX_ENTRIES]; 113 118 /** @} */ 114 } VIRTIO_DESC_CHAIN_T; 115 /** Pointer to a Virtio descriptor chain. */ 116 typedef VIRTIO_DESC_CHAIN_T *PVIRTIO_DESC_CHAIN_T; 117 /** Pointer to a Virtio descriptor chain pointer. */ 118 typedef VIRTIO_DESC_CHAIN_T **PPVIRTIO_DESC_CHAIN_T; 119 /** Magic value for VIRTIO_DESC_CHAIN_T::u32Magic. */ 120 #define VIRTIO_DESC_CHAIN_MAGIC UINT32_C(0x19600219) 119 } VIRTQBUF_T; 120 121 /** Pointers to a Virtio descriptor chain. */ 122 typedef VIRTQBUF_T *PVIRTQBUF, **PPVIRTQBUF; 123 /** Magic value for VIRTQBUF_T::u32Magic. */ 124 #define VIRTQBUF_MAGIC UINT32_C(0x19600219) 121 125 122 126 typedef struct VIRTIOPCIPARAMS … … 187 191 typedef struct VIRTQSTATE 188 192 { 189 uint16_t idxVirtq; /**< Index of this queue */193 uint16_t uVirtqNbr; /**< Index of this queue */ 190 194 char szVirtqName[32]; /**< Dev-specific name of queue */ 191 195 uint16_t uAvailIdxShadow; /**< Consumer's position in avail ring */ … … 348 352 * @param pVirtio Pointer to the shared virtio state. 349 353 * @param pVirtioCC Pointer to the ring-3 virtio state. 350 * @param idxVirtqIndex of the notified queue354 * @param uVirtqNbr Index of the notified queue 351 355 */ 352 DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);356 DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 353 357 354 358 /** @} */ … … 381 385 * @param pVirtio Pointer to the shared virtio state. 382 386 * @param pVirtioCC Pointer to the ring-3 virtio state. 383 * @param idxVirtqIndex of the notified queue387 * @param uVirtqNbr Index of the notified queue 384 388 */ 385 DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq);389 DECLCALLBACKMEMBER(void, pfnVirtqNotified)(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 386 390 387 391 } VIRTIOCORER0; … … 405 409 * @{ */ 406 410 407 int virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq); 408 uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq); 409 void virtioCoreVirtqEnable(PVIRTIOCORE pVirtio, uint16_t idxVirtq, bool fEnable); 410 void virtioCoreVirtqNotifyEnable(PVIRTIOCORE pVirtio, uint16_t idxVirtq, bool fEnable); 411 412 /** 413 * Initiate orderly reset procedure. This is an exposed API for clients that might need it. 414 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2) 415 * 416 * @param pVirtio Pointer to the virtio state. 417 */ 418 void virtioCoreResetAll(PVIRTIOCORE pVirtio); 419 420 /** 421 * 'Attaches' the inheriting device-specific code's queue state to the VirtIO core 422 * queue management, informing the core of the name of the queue and number. The VirtIO core 423 * allocates the queue state information so it can handle all the core VirtiIO queue operations 424 * and dispatch callbacks, etc... 425 * 426 * @param pVirtio Pointer to the shared virtio state. 427 * @param uVirtqNbr Virtq number 428 * @param pcszName Name to give queue 429 * 430 * @returns VBox status code. 431 */ 432 int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, const char *pcszName); 433 434 /** 435 * Enables or disables a virtq 436 * 437 * @param pVirtio Pointer to the shared virtio state. 438 * @param uVirtqNbr Virtq number 439 * @param fEnable Flags whether to enable or disable the virtq 440 * 441 */ 442 443 void virtioCoreVirtqEnable(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable); 444 445 /** 446 * Enable or Disable notification for the specified queue 447 * 448 * @param pVirtio Pointer to the shared virtio state. 449 * @param uVirtqNbr Virtq number 450 * @param fEnable Selects notification mode (enabled or disabled) 451 */ 452 void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable); 453 454 /* 455 * Notifies guest (via ISR or MSI-X) of device configuration change 456 * 457 * @param pVirtio Pointer to the shared virtio state. 458 */ 411 459 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio); 412 void virtioCoreResetAll(PVIRTIOCORE pVirtio); 460 461 /* 462 * Displays the VirtIO spec-related features offered by the core component, 463 * as well as which features have been negotiated and accepted or declined by the guest driver, 464 * providing a summary view of the configuration the device is operating with. 465 * 466 * @param pVirtio Pointer to the shared virtio state. 467 * @param pHlp Pointer to the debug info hlp struct 468 */ 413 469 void virtioCorePrintFeatures(VIRTIOCORE *pVirtio, PCDBGFINFOHLP pHlp); 414 470 415 uint32_t virtioCoreR3DescChainRetain(PVIRTIO_DESC_CHAIN_T pDescChain); 416 uint32_t virtioCoreR3DescChainRelease(PVIRTIOCORE pVirtio, PVIRTIO_DESC_CHAIN_T pDescChain); 417 void virtioCoreR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs); 418 void virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int idxVirtq); 419 int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t idxVirtq, const char *pcszName); 420 421 int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, 422 uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain); 423 424 int virtioCoreR3VirtqPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, 425 PPVIRTIO_DESC_CHAIN_T ppDescChain); 426 427 int virtioCoreR3VirtqSkip(PVIRTIOCORE pVirtio, uint16_t idxVirtq); 428 429 int virtioCoreR3VirtqGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, 430 PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove); 431 432 int virtioCoreR3VirtqPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxVirtq, PRTSGBUF pSgVirtReturn, 433 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence); 434 471 /* 472 * Debuging assist feature displays the state of the VirtIO core code, which includes 473 * an overview of the state of all of the queues. 474 * 475 * This can be invoked when running the VirtualBox debugger, or from the command line 476 * using the command: "VboxManage debugvm <VM name or id> info <device name> [args]" 477 * 478 * Example: VBoxManage debugvm myVnetVm info "virtio-net" all 479 * 480 * This is implemented currently to be invoked by the inheriting device-specific code 481 * (see DevVirtioNet for an example, which receives the debugvm command directly). 482 * That devices lists the available sub-options if no arguments are provided. In that 483 * example this virtq info related function is invoked hierarchically when virtio-net 484 * displays its device-specific queue info. 485 * 486 * @param pDevIns The device instance. 487 * @param pHlp Pointer to the debug info hlp struct 488 * @param pszArgs Arguments to function 489 */ 490 void virtioCoreR3VirtqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int uVirtqNbr); 491 492 /* 493 * Returns the number of avail bufs in the virtq. 494 * 495 * @param pDevIns The device instance. 496 * @param pVirtio Pointer to the shared virtio state. 497 * @param uVirtqNbr Virtqueue to return the count of buffers available for. 498 */ 499 uint16_t virtioCoreVirtqAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 500 501 /** 502 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor 503 * chain into its OUT (to device) and IN to guest components, but does NOT remove it from 504 * the 'avail' queue. I.e. doesn't advance the index. This can be used with virtioVirtqSkip(), 505 * which *does* advance the avail index. Together they facilitate a mechanism that allows 506 * work with a queue element (descriptor chain) to be aborted if necessary, by not advancing 507 * the pointer, or, upon success calling the skip function (above) to move to the next element. 508 * 509 * Additionally it converts the OUT desc chain data to a contiguous virtual 510 * memory buffer for easy consumption by the caller. The caller must return the 511 * descriptor chain pointer via virtioCoreR3VirtqBufPut() and then call virtioCoreVirtqSync() 512 * at some point to return the data to the guest and complete the transaction. 513 * 514 * @param pDevIns The device instance. 515 * @param pVirtio Pointer to the shared virtio state. 516 * @param uVirtqNbr Virtq number 517 * @param ppVirtqBuf Address to store pointer to descriptor chain that contains the 518 * pre-processed transaction information pulled from the virtq. 519 * 520 * @returns VBox status code: 521 * @retval VINF_SUCCESS Success 522 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted). 523 * @retval VERR_NOT_AVAILABLE If the queue is empty. 524 */ 525 int virtioCoreR3VirtqBufPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 526 PPVIRTQBUF ppVirtqBuf); 527 528 /** 529 * Fetches the next descriptor chain using avail ring of indicated queue and converts the descriptor 530 * chain into its OUT (to device) and IN to guest components. 531 * 532 * Additionally it converts the OUT desc chain data to a contiguous virtual 533 * memory buffer for easy consumption by the caller. The caller must return the 534 * descriptor chain pointer via virtioCoreR3VirtqBufPut() and then call virtioCoreVirtqSync() 535 * at some point to return the data to the guest and complete the transaction. 536 * 537 * @param pDevIns The device instance. 538 * @param pVirtio Pointer to the shared virtio state. 539 * @param uVirtqNbr Virtq number 540 * @param ppVirtqBuf Address to store pointer to descriptor chain that contains the 541 * pre-processed transaction information pulled from the virtq. 542 * Returned reference must be released by calling 543 * virtioCoreR3VirtqBufRelease(). 544 * @param fRemove flags whether to remove desc chain from queue (false = peek) 545 * 546 * @returns VBox status code: 547 * @retval VINF_SUCCESS Success 548 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted). 549 * @retval VERR_NOT_AVAILABLE If the queue is empty. 550 */ 551 int virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 552 PPVIRTQBUF ppVirtqBuf, bool fRemove); 553 554 555 /** 556 * Fetches a specific descriptor chain using avail ring of indicated queue and converts the descriptor 557 * chain into its OUT (to device) and IN to guest components. 558 * 559 * Additionally it converts the OUT desc chain data to a contiguous virtual 560 * memory buffer for easy consumption by the caller. The caller must return the 561 * descriptor chain pointer via virtioCoreR3VirtqBufPut() and then call virtioCoreVirtqSync() 562 * at some point to return the data to the guest and complete the transaction. 563 * 564 * @param pDevIns The device instance. 565 * @param pVirtio Pointer to the shared virtio state. 566 * @param uVirtqNbr Virtq number 567 * @param ppVirtqBuf Address to store pointer to descriptor chain that contains the 568 * pre-processed transaction information pulled from the virtq. 569 * Returned reference must be released by calling 570 * virtioCoreR3VirtqBufRelease(). 571 * @param fRemove flags whether to remove desc chain from queue (false = peek) 572 * 573 * @returns VBox status code: 574 * @retval VINF_SUCCESS Success 575 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted). 576 * @retval VERR_NOT_AVAILABLE If the queue is empty. 577 */ 578 579 int virtioCoreR3VirtqBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, 580 uint16_t uHeadIdx, PPVIRTQBUF ppVirtqBuf); 581 582 /** 583 * Returns data to the guest to complete a transaction initiated by virtVirtqGet(). 584 * 585 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments 586 * and a pointer to the descriptor chain context originally derived from the pulled 587 * queue entry, and this function will write the virtual memory s/g buffer into the 588 * guest's physical memory free the descriptor chain. The caller handles the freeing 589 * (as needed) of the virtual memory buffer. 590 * 591 * @note This does a write-ahead to the used ring of the guest's queue. The data 592 * written won't be seen by the guest until the next call to virtioCoreVirtqSync() 593 * 594 * 595 * @param pDevIns The device instance (for reading). 596 * @param pVirtio Pointer to the shared virtio state. 597 * @param uVirtqNbr Virtq number 598 * 599 * @param pSgVirtReturn Points to scatter-gather buffer of virtual memory 600 * segments the caller is returning to the guest. 601 * 602 * @param pVirtqBuf This contains the context of the scatter-gather 603 * buffer originally pulled from the queue. 604 * 605 * @param fFence If true, put up copy fence (memory barrier) after 606 * copying to guest phys. mem. 607 * 608 * @returns VBox status code. 609 * @retval VINF_SUCCESS Success 610 * @retval VERR_INVALID_STATE VirtIO not in ready state 611 * @retval VERR_NOT_AVAILABLE Virtq is empty 612 * 613 * @note This function will not release any reference to pVirtqBuf. The 614 * caller must take care of that. 615 */ 616 617 int virtioCoreR3VirtqBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, PRTSGBUF pSgVirtReturn, 618 PVIRTQBUF pVirtqBuf, bool fFence); 619 620 /** 621 * Skip the next entry in the specified queue (typically used with virtioCoreR3VirtqBufPeek()) 622 * 623 * @param pVirtio Pointer to the virtio state. 624 * @param uVirtqNbr Index of queue 625 */ 626 int virtioCoreR3VirtqBufSkip(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 627 628 /** 629 * Updates the indicated virtq's "used ring" descriptor index to match the 630 * current write-head index, thus exposing the data added to the used ring by all 631 * virtioCoreR3VirtqBufPut() calls since the last sync. This should be called after one or 632 * more virtioCoreR3VirtqBufPut() calls to inform the guest driver there is data in the queue. 633 * Explicit notifications (e.g. interrupt or MSI-X) will be sent to the guest, 634 * depending on VirtIO features negotiated and conditions, otherwise the guest 635 * will detect the update by polling. (see VirtIO 1.0 specification, Section 2.4 "Virtqueues"). 636 * 637 * @param pDevIns The device instance. 638 * @param pVirtio Pointer to the shared virtio state. 639 * @param uVirtqNbr Virtq number 640 * 641 * @returns VBox status code. 642 * @retval VINF_SUCCESS Success 643 * @retval VERR_INVALID_STATE VirtIO not in ready state 644 */ 645 int virtioCoreVirtqSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 646 647 /** 648 * Retains a reference to the given descriptor chain. 649 * 650 * @returns New reference count. 651 * @retval UINT32_MAX on invalid parameter. 652 * @param pVirtqBuf The descriptor chain to reference. 653 */ 654 uint32_t virtioCoreR3VirtqBufRetain(PVIRTQBUF pVirtqBuf); 655 656 /** 657 * Releases a reference to the given descriptor chain. 658 * 659 * @returns New reference count. 660 * @retval 0 if freed or invalid parameter. 661 * @param pVirtio Pointer to the shared virtio state. 662 * @param pVirtqBuf The descriptor chain to reference. NULL is quietly 663 * ignored (returns 0). 664 */ 665 uint32_t virtioCoreR3VirtqBufRelease(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf); 435 666 436 667 /** … … 438 669 * 439 670 * @param pVirtio Pointer to the virtio state. 440 * @param idxVirtqVirtq number.441 * @returns 442 */ 443 DECLINLINE(bool) virtioCoreIsVirtqEnabled(PVIRTIOCORE pVirtio, uint16_t idxVirtq)444 { 445 Assert( idxVirtq< RT_ELEMENTS(pVirtio->aVirtqState));446 return pVirtio->uVirtqEnable[ idxVirtq] != 0;671 * @param uVirtqNbr Virtq number. 672 * @returns true or false indicating whether to enable queue or not 673 */ 674 DECLINLINE(bool) virtioCoreIsVirtqEnabled(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 675 { 676 Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 677 return pVirtio->uVirtqEnable[uVirtqNbr] != 0; 447 678 } 448 679 449 680 /** 450 * Get name of queue, by idxVirtq, assigned at virtioCoreR3VirtqAttach()681 * Get name of queue, by uVirtqNbr, assigned at virtioCoreR3VirtqAttach() 451 682 * 452 683 * @param pVirtio Pointer to the virtio state. 453 * @param idxVirtqVirtq number.684 * @param uVirtqNbr Virtq number. 454 685 * 455 686 * @returns Pointer to read-only queue name. 456 687 */ 457 DECLINLINE(const char *) virtioCoreVirtqGetName(PVIRTIOCORE pVirtio, uint16_t idxVirtq)458 { 459 Assert((size_t) idxVirtq< RT_ELEMENTS(pVirtio->aVirtqState));460 return pVirtio->aVirtqState[ idxVirtq].szVirtqName;688 DECLINLINE(const char *) virtioCoreVirtqGetName(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 689 { 690 Assert((size_t)uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqState)); 691 return pVirtio->aVirtqState[uVirtqNbr].szVirtqName; 461 692 } 462 693 … … 470 701 return pVirtio->uDriverFeatures; 471 702 } 472 473 703 474 704 /** … … 486 716 } 487 717 488 void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize, 718 /** 719 * Log memory-mapped I/O input or output value. 720 * 721 * This is to be invoked by macros that assume they are invoked in functions with 722 * the relevant arguments. (See Virtio_1_0.cpp). 723 * 724 * It is exposed via the API so inheriting device-specific clients can provide similar 725 * logging capabilities for a consistent look-and-feel. 726 * 727 * @param pszFunc To avoid displaying this function's name via __FUNCTION__ or LogFunc() 728 * @param pszMember Name of struct member 729 * @param pv pointer to value 730 * @param cb size of value 731 * @param uOffset offset into member where value starts 732 * @param fWrite True if write I/O 733 * @param fHasIndex True if the member is indexed 734 * @param idx The index if fHasIndex 735 */ 736 const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState);void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize, 489 737 const void *pv, uint32_t cb, uint32_t uOffset, 490 738 int fWrite, int fHasIndex, uint32_t idx); 491 739 492 /* Debug assist functions for consumer device code */ 740 /** 741 * Debug assist for any consumer device code that inherits VIRTIOCORE 742 * 743 * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to 744 * control enabling of logging efficiently. 745 * 746 * @param pv pointer to buffer to dump contents of 747 * @param cb count of characters to dump from buffer 748 * @param uBase base address of per-row address prefixing of hex output 749 * @param pszTitle Optional title. If present displays title that lists 750 * provided text with value of cb to indicate size next to it. 751 */ 493 752 void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle); 753 754 /** 755 * Debug assist for any consumer device code that inherits VIRTIOCORE 756 & 757 * Do a hex dump of memory in guest physical context 758 * 759 * @param GCPhys pointer to buffer to dump contents of 760 * @param cb count of characters to dump from buffer 761 * @param uBase base address of per-row address prefixing of hex output 762 * @param pszTitle Optional title. If present displays title that lists 763 * provided text with value of cb to indicate size next to it. 764 */ 494 765 void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle); 495 766 496 767 /** The following virtioCoreSgBuf*() functions mimic the functionality of the related RT s/g functions, 768 * except they work with the data type GCPhys rather than void * 769 */ 497 770 void virtioCoreSgBufInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs); 498 771 void virtioCoreSgBufReset(PVIRTIOSGBUF pGcSgBuf); … … 504 777 size_t virtioCoreSgBufCalcTotalLength(PVIRTIOSGBUF pGcSgBuf); 505 778 779 /** Misc VM and PDM boilerplate */ 506 780 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); 507 781 int virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); … … 511 785 const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg); 512 786 int virtioCoreRZInit(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio); 787 788 513 789 const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState); 514 790
Note:
See TracChangeset
for help on using the changeset viewer.