- Timestamp:
- Aug 8, 2019 7:26:33 AM (5 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r80169 r80194 60 60 #define VIRTIOSCSI_REGION_PCI_CAP 2 61 61 62 63 64 62 /** 65 63 * This macro resolves to boolean true if uOffset matches a field offset and size exactly, 66 64 * (or if it is a 64-bit field, if it accesses either 32-bit part as a 32-bit access) 67 65 * ASSUMED this critereon is mandated by section 4.1.3.1 of the VirtIO 1.0 specification) 66 * This MACRO can be re-written to allow unaligned access to a field (within bounds). 68 67 * 69 68 * @param member - Member of VIRTIO_PCI_COMMON_CFG_T … … 72 71 * @result - true or false 73 72 */ 74 #define VIRTIO_1_0__SECT_4_1_3_1__COMPLIANT 75 #ifdef VIRTIO_1_0__SECT_4_1_3_1__COMPLIANT 76 # define MATCH_SCSI_CONFIG(member) \ 73 #define MATCH_SCSI_CONFIG(member) \ 77 74 (RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member) == 64 \ 78 75 && ( uOffset == RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \ … … 81 78 || (uOffset == RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \ 82 79 && cb == RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member)) 83 #else84 # define MATCH_SCSI_CONFIG(member) \85 ((int)uOffset >= RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \86 && uOffset < (uint32_t)(RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member) \87 + RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member)) \88 && cb <= RT_SIZEOFMEMB(VIRTIO_SCSI_CONFIG_T, member) \89 - (uOffset - RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member)))90 #endif91 80 92 81 #define LOG_ACCESSOR(member) \ … … 97 86 uint32_t uMemberOffset = uOffset - RT_OFFSETOF(VIRTIO_SCSI_CONFIG_T, member); \ 98 87 if (fWrite) \ 99 memcpy(((char *)&p This->virtioScsiConfig.member) + uMemberOffset, (const char *)pv, cb); \88 memcpy(((char *)&pVirtioScsi->virtioScsiConfig.member) + uMemberOffset, (const char *)pv, cb); \ 100 89 else \ 101 memcpy((char *)pv, (const char *)(((char *)&p This->virtioScsiConfig.member) + uMemberOffset), cb); \90 memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uMemberOffset), cb); \ 102 91 LOG_ACCESSOR(member); \ 103 92 } … … 110 99 else \ 111 100 { \ 112 memcpy((char *)pv, (const char *)(((char *)&p This->virtioScsiConfig.member) + uMemberOffset), cb); \101 memcpy((char *)pv, (const char *)(((char *)&pVirtioScsi->virtioScsiConfig.member) + uMemberOffset), cb); \ 113 102 LOG_ACCESSOR(member); \ 114 103 } \ … … 346 335 typedef struct VIRTIOSCSI 347 336 { 348 /* virtioState must be first member*/349 VIRTIO STATE virtioState;337 /* Opaque handle to Virtio common framework */ 338 VIRTIOHANDLE hVirtio; 350 339 351 340 /* SCSI target instances data */ … … 783 772 } 784 773 785 static int virtioScsiR3CfgAccessed(PVIRTIOSCSI p This, uint32_t uOffset,774 static int virtioScsiR3CfgAccessed(PVIRTIOSCSI pVirtioScsi, uint32_t uOffset, 786 775 const void *pv, size_t cb, uint8_t fWrite) 787 776 { … … 856 845 { 857 846 int rc = VINF_SUCCESS; 858 PVIRTIOSCSI p This= PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);847 PVIRTIOSCSI pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 859 848 860 849 // LogFunc(("Read from Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n", 861 850 // uOffset, cb)); 862 851 863 rc = virtioScsiR3CfgAccessed(p This, uOffset, pv, cb, false);852 rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, false); 864 853 865 854 return rc; … … 878 867 { 879 868 int rc = VINF_SUCCESS; 880 PVIRTIOSCSI p This= PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);869 PVIRTIOSCSI pVirtioScsi = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 881 870 882 871 // LogFunc(("Write to Device-Specific capabilities: uOffset: 0x%x, cb: 0x%x\n", 883 872 // uOffset, cb)); 884 873 885 rc = virtioScsiR3CfgAccessed(p This, uOffset, pv, cb, true);874 rc = virtioScsiR3CfgAccessed(pVirtioScsi, uOffset, pv, cb, true); 886 875 887 876 return rc; … … 1102 1091 pVirtioPciParams->uInterruptPin = 0x01; 1103 1092 1104 PVIRTIOSTATE pVirtio = &(pThis->virtioState);1105 1106 virtioSetHostFeatures(pVirtio, VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED);1107 1108 1093 pThis->IBase.pfnQueryInterface = virtioScsiR3DeviceQueryInterface; 1109 1094 … … 1120 1105 pThis->virtioScsiConfig.uMaxLun = 16383; /* from VirtIO 1.0 spec */ 1121 1106 1122 rc = virtioConstruct(pDevIns, pVirtio, iInstance, pVirtioPciParams,1107 rc = virtioConstruct(pDevIns, &pThis->hVirtio, iInstance, pVirtioPciParams, 1123 1108 VIRTIOSCSI_NAME_FMT, VIRTIOSCSI_N_QUEUES, VIRTIOSCSI_REGION_PCI_CAP, 1109 VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED, 1124 1110 virtioScsiR3DevCapRead, virtioScsiR3DevCapWrite, 1125 1111 sizeof(VIRTIO_SCSI_CONFIG_T) /* cbDevSpecificCap */, 1126 true /* fHaveDevSpecificCap */,1112 (void *)&pThis->virtioScsiConfig /* pDevSpecificCap */, 1127 1113 0 /* uNotifyOffMultiplier */); 1128 1114 -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r80168 r80194 1 1 /* $Id$ */ 2 2 /** @file 3 * Virtio_1_0 - Virtio Common Functions (VirtQ ueue, VQueue, Virtio PCI)3 * Virtio_1_0 - Virtio Common Functions (VirtQ, VQueue, Virtio PCI) 4 4 */ 5 5 … … 26 26 #include <iprt/assert.h> 27 27 #include <iprt/uuid.h> 28 #include <iprt/mem.h> 28 29 #include <VBox/vmm/pdmdev.h> 30 #include "Virtio_1_0_impl.h" 29 31 #include "Virtio_1_0.h" 30 #include "Virtio_1_0_impl.h"31 32 32 33 #define INSTANCE(pState) pState->szInstance 33 34 #define IFACE_TO_STATE(pIface, ifaceName) ((VIRTIOSTATE *)((char*)(pIface) - RT_UOFFSETOF(VIRTIOSTATE, ifaceName))) 35 36 #define H2P(hVirtio) ((PVIRTIOSTATE)(hVirtio)) 34 37 35 38 #ifdef LOG_ENABLED … … 37 40 #endif 38 41 39 void virtQueueReadDesc(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue, uint32_t idx, PVIRTQUEUEDESC pDesc) 40 { 41 //Log(("%s virtQueueReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVirtQueue, idx)); 42 /** 43 * Formats the logging of a memory-mapped I/O input or output value 44 * 45 * @param pszFunc - To avoid displaying this function's name via __FUNCTION__ or LogFunc() 46 * @param pszMember - Name of struct member 47 * @param pv - pointer to value 48 * @param cb - size of value 49 * @param uOffset - offset into member where value starts 50 * @param fWrite - True if write I/O 51 * @param fHasIndex - True if the member is indexed 52 * @param idx - The index if fHasIndex 53 */ 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]; 62 63 #define MAX_STRING 64 64 char pszIdx[MAX_STRING] = { 0 }; 65 char pszDepiction[MAX_STRING] = { 0 }; 66 char pszFormattedVal[MAX_STRING] = { 0 }; 67 if (fHasIndex) 68 RTStrPrintf(pszIdx, sizeof(pszIdx), "[%d]", idx); 69 if (cb == 1 || cb == 2 || cb == 4 || cb == 8) 70 { 71 /* manually padding with 0's instead of \b due to different impl of %x precision than printf() */ 72 uint64_t val = 0; 73 memcpy((char *)&val, pv, cb); 74 FMTHEX(pszFormattedVal, val, cb * 2); 75 if (uOffset != 0) /* display bounds if partial member access */ 76 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]", 77 pszMember, pszIdx, uOffset, uOffset + cb - 1); 78 else 79 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s", pszMember, pszIdx); 80 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%-30s", pszDepiction); 81 uint32_t first = 0; 82 for (uint8_t i = 0; i < sizeof(pszDepiction); i++) 83 if (pszDepiction[i] == ' ' && first++ != 0) 84 pszDepiction[i] = '.'; 85 Log(("%s: Guest %s %s 0x%s\n", \ 86 pszFunc, fWrite ? "wrote" : "read ", pszDepiction, pszFormattedVal)); 87 } 88 else /* odd number or oversized access, ... log inline hex-dump style */ 89 { 90 Log(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n", \ 91 pszFunc, fWrite ? "wrote" : "read ", pszMember, 92 pszIdx, uOffset, uOffset + cb, cb, pv)); 93 } 94 } 95 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)); 42 100 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 43 pVirtQ ueue->pGcPhysVirtqDescriptors + sizeof(VIRTQUEUEDESC) * (idx % pVirtQueue->cbQueue),44 pDesc, sizeof(VIRTQ UEUEDESC));45 } 46 47 uint16_t virtQueueReadAvail(PVIRTIOSTATE pState, PVIRTQ UEUE pVirtQueue, uint32_t idx)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) 48 106 { 49 107 uint16_t tmp; 50 108 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 51 pVirtQ ueue->pGcPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQUEUEAVAIL, auRing[idx % pVirtQueue->cbQueue]),109 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[idx % pVirtQ->cbQueue]), 52 110 &tmp, sizeof(tmp)); 53 111 return tmp; 54 112 } 55 113 56 uint16_t virtQueueReadAvailFlags(PVIRTIOSTATE pState, PVIRTQ UEUE pVirtQueue)114 uint16_t virtQueueReadAvailFlags(PVIRTIOSTATE pState, PVIRTQ pVirtQ) 57 115 { 58 116 uint16_t tmp; 59 117 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 60 pVirtQ ueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEAVAIL, fFlags),118 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags), 61 119 &tmp, sizeof(tmp)); 62 120 return tmp; 63 121 } 64 122 65 uint16_t virtQueueReadUsedIndex(PVIRTIOSTATE pState, PVIRTQ UEUE pVirtQueue)123 uint16_t virtQueueReadUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ) 66 124 { 67 125 uint16_t tmp; 68 126 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 69 pVirtQ ueue->pGcPhysVirtqUsed + RT_UOFFSETOF(VIRTQUEUEUSED, uIdx),127 pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx), 70 128 &tmp, sizeof(tmp)); 71 129 return tmp; 72 130 } 73 131 74 void virtQueueWriteUsedIndex(PVIRTIOSTATE pState, PVIRTQ UEUE pVirtQueue, uint16_t u16Value)132 void virtQueueWriteUsedIndex(PVIRTIOSTATE pState, PVIRTQ pVirtQ, uint16_t u16Value) 75 133 { 76 134 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 77 pVirtQ ueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEUSED, uIdx),135 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uIdx), 78 136 &u16Value, sizeof(u16Value)); 79 137 } 80 138 81 void virtQueueWriteUsedElem(PVIRTIOSTATE pState, PVIRTQ UEUE pVirtQueue, uint32_t idx, uint32_t id, uint32_t uLen)82 { 83 84 RT_NOREF5(pState, pVirtQ ueue, idx, id, uLen);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); 85 143 /* PK TODO: Adapt to VirtIO 1.0 86 VIRTQ UEUEUSEDELEMelem;144 VIRTQ_USED_ELEM_T elem; 87 145 88 146 elem.id = id; 89 147 elem.uLen = uLen; 90 148 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 91 pVirtQ ueue->pGcPhysVirtqUsed + RT_UOFFSETOF_DYN(VIRTQUEUEUSED, ring[idx % pVirtQueue->cbQueue]),149 pVirtQ->pGcPhysVirtqUsed + RT_UOFFSETOF_DYN(VIRTQ_USED_T, ring[idx % pVirtQ->cbQueue]), 92 150 &elem, sizeof(elem)); 93 151 */ 94 152 } 95 153 96 void virtQueueSetNotification(PVIRTIOSTATE pState, PVIRTQ UEUE pVirtQueue, bool fEnabled)97 { 98 RT_NOREF3(pState, pVirtQ ueue, fEnabled);154 void virtQueueSetNotification(PVIRTIOSTATE pState, PVIRTQ pVirtQ, bool fEnabled) 155 { 156 RT_NOREF3(pState, pVirtQ, fEnabled); 99 157 100 158 /* PK TODO: Adapt to VirtIO 1.0 … … 102 160 103 161 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 104 pVirtQ ueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEUSED, uFlags),162 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags), 105 163 &tmp, sizeof(tmp)); 106 164 107 165 if (fEnabled) 108 tmp &= ~ VIRTQ UEUEUSED_F_NO_NOTIFY;166 tmp &= ~ VIRTQ_USED_T_F_NO_NOTIFY; 109 167 else 110 tmp |= VIRTQ UEUEUSED_F_NO_NOTIFY;168 tmp |= VIRTQ_USED_T_F_NO_NOTIFY; 111 169 112 170 PDMDevHlpPCIPhysWrite(pState->CTX_SUFF(pDevIns), 113 pVirtQ ueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEUSED, uFlags),171 pVirtQ->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_USED_T, uFlags), 114 172 &tmp, sizeof(tmp)); 115 173 */ … … 145 203 QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex)); 146 204 147 VIRTQ UEUEDESCdesc;148 uint16_t idx = virtQueueReadAvail(pState, &pQueue->VirtQ ueue, pQueue->uNextAvailIndex);205 VIRTQ_DESC_T desc; 206 uint16_t idx = virtQueueReadAvail(pState, &pQueue->VirtQ, pQueue->uNextAvailIndex); 149 207 if (fRemove) 150 208 pQueue->uNextAvailIndex++; … … 160 218 // total number of descriptors in the ring (see @bugref{8620}). 161 219 /// 162 if (pElem->nIn + pElem->nOut >= VIRTQ UEUE_MAX_SIZE)220 if (pElem->nIn + pElem->nOut >= VIRTQ_MAX_SIZE) 163 221 { 164 222 static volatile uint32_t s_cMessages = 0; … … 177 235 RT_UNTRUSTED_VALIDATED_FENCE(); 178 236 179 virtQueueReadDesc(pState, &pQueue->VirtQ ueue, idx, &desc);180 if (desc.u16Flags & VIRTQ UEUEDESC_F_WRITE)237 virtQueueReadDesc(pState, &pQueue->VirtQ, idx, &desc); 238 if (desc.u16Flags & VIRTQ_DESC_T_F_WRITE) 181 239 { 182 240 Log2(("%s virtQueueGet: %s IN seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState), … … 196 254 197 255 idx = desc.next; 198 } while (desc.u16Flags & VIRTQ UEUEDESC_F_NEXT);256 } while (desc.u16Flags & VIRTQ_DESC_T_F_NEXT); 199 257 200 258 Log2(("%s virtQueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState), … … 261 319 " used_idx=%u guest_used_idx=%u id=%u len=%u\n", 262 320 INSTANCE(pState), QUEUENAME(pState, pQueue), 263 pQueue->uNextUsedIndex, virtQueueReadUsedIndex(pState, &pQueue->VirtQ ueue),321 pQueue->uNextUsedIndex, virtQueueReadUsedIndex(pState, &pQueue->VirtQ), 264 322 pElem->idx, uTotalLen)); 265 323 266 virtQueueWriteUsedElem(pState, &pQueue->VirtQ ueue,324 virtQueueWriteUsedElem(pState, &pQueue->VirtQ, 267 325 pQueue->uNextUsedIndex++, 268 326 pElem->idx, uTotalLen); … … 279 337 LogFlow(("%s virtQueueNotify: %s availFlags=%x guestFeatures=%x virtQueue is %sempty\n", 280 338 INSTANCE(pState), QUEUENAME(pState, pQueue), 281 virtQueueReadAvailFlags(pState, &pQueue->VirtQ ueue),339 virtQueueReadAvailFlags(pState, &pQueue->VirtQ), 282 340 pState->uGuestFeatures, virtQueueIsEmpty(pState, pQueue)?"":"not ")); 283 if (!(virtQueueReadAvailFlags(pState, &pQueue->VirtQ ueue) & VIRTQUEUEAVAIL_F_NO_INTERRUPT)341 if (!(virtQueueReadAvailFlags(pState, &pQueue->VirtQ) & VIRTQ_AVAIL_T_F_NO_INTERRUPT) 284 342 || ((pState->uGuestFeatures & VIRTIO_F_NOTIFY_ON_EMPTY) && virtQueueIsEmpty(pState, pQueue))) 285 343 { … … 296 354 /* PK TODO Adapt to VirtIO 1.0 297 355 Log2(("%s virtQueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState), 298 QUEUENAME(pState, pQueue), virtQueueReadUsedIndex(pState, &pQueue->VirtQ ueue), pQueue->uNextUsedIndex));299 virtQueueWriteUsedIndex(pState, &pQueue->VirtQ ueue, pQueue->uNextUsedIndex);356 QUEUENAME(pState, pQueue), virtQueueReadUsedIndex(pState, &pQueue->VirtQ), pQueue->uNextUsedIndex)); 357 virtQueueWriteUsedIndex(pState, &pQueue->VirtQ, pQueue->uNextUsedIndex); 300 358 virtQueueNotify(pState, pQueue); 301 359 */ 302 360 } 303 361 304 int virtioReset(PVIRTIOSTATE pVirtio) 305 { 306 RT_NOREF(pVirtio); 307 /* PK TODO Adapt to VirtIO 1.09 308 pState->uGuestFeatures = 0; 309 pState->uQueueSelector = 0; 310 pState->uStatus = 0; 311 pState->uISR = 0; 312 313 for (unsigned i = 0; i < pState->nQueues; i++) 314 virtQueueReset(&pState->Queues[i]); 315 */ 316 virtioNotify(pVirtio); 317 return VINF_SUCCESS; 318 } 362 319 363 320 364 /** … … 383 427 * @param uPass The data pass. 384 428 */ 385 int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t nQueues)386 { 387 RT_NOREF5(pVirtio, pSSM, uVersion, uPass, nQueues);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); 388 432 int rc = VINF_SUCCESS; 389 433 virtioDumpState(pVirtio, "virtioLoadExec"); … … 419 463 { 420 464 RT_NOREF(offDelta); 421 VIRTIOSTATE *pState = PDMINS_2_DATA(pDevIns, VIRTIOSTATE*); 422 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 465 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 466 467 pVirtio->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 423 468 // TBD 424 469 } 425 470 426 PVQUEUE virtioAddQueue(VIRTIOSTATE* pState, unsigned cbQueue, PFNVIRTIOQUEUECALLBACK pfnCallback,const char *pcszName)427 { 428 429 RT_NOREF 4(pState, cbQueue, pfnCallback, pcszName);471 PVQUEUE virtioAddQueue(VIRTIOSTATE* pState, unsigned cbQueue, const char *pcszName) 472 { 473 474 RT_NOREF3(pState, cbQueue, pcszName); 430 475 /* PK TODO Adapt to VirtIO 1.0 431 476 432 477 PVQUEUE pQueue = NULL; 433 478 // Find an empty queue slot 434 for (unsigned i = 0; i < pState-> nQueues; i++)435 { 436 if (pState->Queues[i].VirtQ ueue.cbQueue == 0)479 for (unsigned i = 0; i < pState->uNumQueues; i++) 480 { 481 if (pState->Queues[i].VirtQ.cbQueue == 0) 437 482 { 438 483 pQueue = &pState->Queues[i]; … … 447 492 else 448 493 { 449 pQueue->VirtQ ueue.cbQueue = cbQueue;450 pQueue->VirtQ ueue.addrDescriptors = 0;494 pQueue->VirtQ.cbQueue = cbQueue; 495 pQueue->VirtQ.addrDescriptors = 0; 451 496 pQueue->uPageNumber = 0; 452 497 pQueue->pfnCallback = pfnCallback; … … 459 504 460 505 506 507 __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 461 530 __attribute__((unused)) 462 531 static void virtQueueReset(PVQUEUE pQueue) … … 464 533 RT_NOREF(pQueue); 465 534 /* PK TODO Adapt to VirtIO 1.0 466 pQueue->VirtQ ueue.addrDescriptors = 0;467 pQueue->VirtQ ueue.addrAvail = 0;468 pQueue->VirtQ ueue.addrUsed = 0;535 pQueue->VirtQ.addrDescriptors = 0; 536 pQueue->VirtQ.addrAvail = 0; 537 pQueue->VirtQ.addrUsed = 0; 469 538 pQueue->uNextAvailIndex = 0; 470 539 pQueue->uNextUsedIndex = 0; … … 473 542 } 474 543 544 /** 545 * Notify driver of a configuration or queue event 546 * 547 * @param pVirtio - Pointer to instance state 548 * @param fConfigChange - True if cfg change notification else, queue notification 549 */ 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; 573 } 574 475 575 __attribute__((unused)) 476 static void virtQueueInit(PVQUEUE pQueue, uint32_t uPageNumber) 477 { 478 RT_NOREF2(pQueue, uPageNumber); 479 480 /* PK TODO, re-work this for VirtIO 1.0 481 pQueue->VirtQueue.addrDescriptors = (uint64_t)uPageNumber << PAGE_SHIFT; 482 483 pQueue->VirtQueue.addrAvail = pQueue->VirtQueue.addrDescriptors 484 + sizeof(VIRTQUEUEDESC) * pQueue->VirtQueue.cbQueue; 485 486 pQueue->VirtQueue.addrUsed = RT_ALIGN(pQueue->VirtQueue.addrAvail 487 + RT_UOFFSETOF_DYN(VIRTQUEUEAVAIL, ring[pQueue->VirtQueue.cbQueue]) 488 + sizeof(uint16_t), // virtio 1.0 adds a 16-bit field following ring data 489 PAGE_SIZE); // The used ring must start from the next page. 490 491 pQueue->uNextAvailIndex = 0; 492 pQueue->uNextUsedIndex = 0; 493 */ 494 495 } 496 497 void virtioNotify(PVIRTIOSTATE pVirtio) 498 { 499 RT_NOREF(pVirtio); 576 static void virtioSetNeedsReset(PVIRTIOSTATE pVirtio) 577 { 578 pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET; 579 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 580 { 581 pVirtio->fGenUpdatePending = true; 582 virtioNotifyDriver(pVirtio, true); 583 } 500 584 } 501 585 502 586 static void virtioResetDevice(PVIRTIOSTATE pVirtio) 503 587 { 504 RT_NOREF(pVirtio); 588 505 589 LogFunc(("\n")); 506 pVirtio->uDeviceStatus = 0; 590 pVirtio->uDeviceStatus = 0; 591 pVirtio->uDeviceFeaturesSelect = 0; 592 pVirtio->uDriverFeaturesSelect = 0; 593 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 } 507 602 } 508 603 … … 603 698 { 604 699 uint32_t uIntraOff = 0; 605 *(uint16_t *)pv = MAX_QUEUES;700 *(uint16_t *)pv = VIRTIO_MAX_QUEUES; 606 701 LOG_ACCESSOR(uNumQueues); 607 702 } … … 696 791 { 697 792 RT_NOREF(pvUser); 698 PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);793 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 699 794 int rc = VINF_SUCCESS; 700 795 … … 710 805 { 711 806 uint32_t uDevSpecificDataOffset = GCPhysAddr - pVirtio->pGcPhysDeviceCap; 807 /** 808 * Callback to client to manage device-specific configuration and changes to it. 809 */ 712 810 rc = pVirtio->virtioCallbacks.pfnVirtioDevCapRead(pDevIns, uDevSpecificDataOffset, pv, cb); 811 /** 812 * Anytime any part of the device-specific configuration (which our client maintains) is read 813 * it needs to be checked to see if it changed since the last time any part was read, in 814 * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1) 815 */ 816 uint32_t fDevSpecificFieldChanged = false; 817 818 if (memcmp((char *)pv + uDevSpecificDataOffset, (char *)pVirtio->pPrevDevSpecificCap + uDevSpecificDataOffset, cb)) 819 fDevSpecificFieldChanged = true; 820 821 memcpy(pVirtio->pPrevDevSpecificCap, pv, pVirtio->cbDevSpecificCap); 822 if (pVirtio->fGenUpdatePending || fDevSpecificFieldChanged) 823 { 824 if (fDevSpecificFieldChanged) 825 LogFunc(("Dev specific config field changed since last read, gen++ = %d\n", 826 pVirtio->uConfigGeneration)); 827 else 828 LogFunc(("Config generation pending flag set, gen++ = %d\n", 829 pVirtio->uConfigGeneration)); 830 ++pVirtio->uConfigGeneration; 831 pVirtio->fGenUpdatePending = false; 832 } 713 833 } 714 834 else … … 745 865 { 746 866 RT_NOREF(pvUser); 747 PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);867 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 748 868 int rc = VINF_SUCCESS; 749 869 … … 790 910 { 791 911 RT_NOREF3(pPciDev, iRegion, enmType); 792 PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);912 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 793 913 int rc = VINF_SUCCESS; 794 914 795 915 Assert(cb >= 32); 796 916 797 if (iRegion == pVirtio->uVirtioCap Region)917 if (iRegion == pVirtio->uVirtioCapBar) 798 918 { 799 919 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */ … … 815 935 pVirtio->pGcPhysNotifyCap = GCPhysAddress + pVirtio->pNotifyCap->pciCap.uOffset; 816 936 pVirtio->pGcPhysIsrCap = GCPhysAddress + pVirtio->pIsrCap->uOffset; 817 if (pVirtio-> fHaveDevSpecificCap)937 if (pVirtio->pDevSpecificCap) 818 938 pVirtio->pGcPhysDeviceCap = GCPhysAddress + pVirtio->pDeviceCap->uOffset; 819 939 } … … 837 957 uint32_t uAddress, unsigned cb) 838 958 { 839 PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE); 959 // PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE); 960 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 840 961 841 962 if (uAddress == (uint64_t)&pVirtio->pPciCfgCap->uPciCfgData) … … 848 969 uint8_t uBar = pVirtio->pPciCfgCap->pciCap.uBar; 849 970 uint32_t pv = 0; 850 if (uBar == pVirtio->uVirtioCap Region)971 if (uBar == pVirtio->uVirtioCapBar) 851 972 (void)virtioR3MmioRead(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->GCPhysPciCapBase + uOffset), 852 973 &pv, uLength); … … 882 1003 uint32_t uAddress, uint32_t u32Value, unsigned cb) 883 1004 { 884 PVIRTIOSTATE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOSTATE);1005 PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *); 885 1006 886 1007 if (uAddress == pVirtio->uPciCfgDataOff) … … 892 1013 uint32_t uOffset = pVirtio->pPciCfgCap->pciCap.uOffset; 893 1014 uint8_t uBar = pVirtio->pPciCfgCap->pciCap.uBar; 894 if (uBar == pVirtio->uVirtioCap Region)1015 if (uBar == pVirtio->uVirtioCapBar) 895 1016 (void)virtioR3MmioWrite(pDevIns, NULL, (RTGCPHYS)((uint32_t)pVirtio->GCPhysPciCapBase + uOffset), 896 1017 (void *)&u32Value, uLength); … … 944 1065 */ 945 1066 946 void virtioSetHostFeatures(PVIRTIOSTATE pVirtio, uint64_t uDeviceFeatures) 947 { 948 pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures; 1067 1068 void virtioSetHostFeatures(VIRTIOHANDLE hVirtio, uint64_t uDeviceFeatures) 1069 { 1070 H2P(hVirtio)->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures; 949 1071 } 950 1072 … … 988 1110 * @param pPciParams Values to populate industry standard PCI Configuration Space data structure 989 1111 * @param pcszNameFmt Device instance name (format-specifier) 990 * @param nQueues Number of Virtio Queues created by consumer (driver)1112 * @param uNumQueues Number of Virtio Queues created by consumer (driver) 991 1113 * @param uVirtioRegion Region number to map for PCi Capabilities structs 992 1114 * @param devCapReadCallback Client function to call back to handle device specific capabilities … … 996 1118 */ 997 1119 998 int virtioConstruct(PPDMDEVINS pDevIns, PVIRTIO STATE pVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams,999 const char *pcszNameFmt, uint32_t nQueues, uint32_t uVirtioCapRegion,1120 int virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOHANDLE phVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams, 1121 const char *pcszNameFmt, uint32_t uNumQueues, uint32_t uVirtioCapBar, uint64_t uDeviceFeatures, 1000 1122 PFNVIRTIODEVCAPREAD devCapReadCallback, PFNVIRTIODEVCAPWRITE devCapWriteCallback, 1001 uint16_t cbDevSpecificCap, bool fHaveDevSpecificCap, uint32_t uNotifyOffMultiplier) 1002 { 1003 pVirtio->nQueues = nQueues; 1123 uint16_t cbDevSpecificCap, void *pDevSpecificCap, uint32_t uNotifyOffMultiplier) 1124 { 1125 1126 int rc = VINF_SUCCESS; 1127 1128 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAlloc(sizeof(VIRTIOSTATE)); 1129 if (!pVirtio) 1130 { 1131 PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("virtio: out of memory")); 1132 return VERR_NO_MEMORY; 1133 } 1134 1135 1136 pVirtio->uNumQueues = uNumQueues; 1004 1137 pVirtio->uNotifyOffMultiplier = uNotifyOffMultiplier; 1138 pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 | uDeviceFeatures; 1005 1139 1006 1140 /* Init handles and log related stuff. */ … … 1012 1146 pVirtio->uDeviceStatus = 0; 1013 1147 pVirtio->cbDevSpecificCap = cbDevSpecificCap; 1014 pVirtio->uVirtioCapRegion = uVirtioCapRegion; 1015 pVirtio->fHaveDevSpecificCap = fHaveDevSpecificCap; 1148 pVirtio->pDevSpecificCap = pDevSpecificCap; 1149 /** 1150 * Need to keep a history of this relatively small virtio device-specific 1151 * configuration buffer, which is opaque to this encapsulation of the generic 1152 * part virtio operations, to track config changes to fields, in order to 1153 * update the configuration generation each change. (See VirtIO 1.0 section 4.1.4.3.1) 1154 */ 1155 pVirtio->pPrevDevSpecificCap = RTMemAlloc(cbDevSpecificCap); 1156 if (!pVirtio->pPrevDevSpecificCap) 1157 { 1158 RTMemFree(pVirtio); 1159 PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("virtio: out of memory")); 1160 return VERR_NO_MEMORY; 1161 } 1162 memcpy(pVirtio->pPrevDevSpecificCap, pVirtio->pDevSpecificCap, cbDevSpecificCap); 1163 pVirtio->uVirtioCapBar = uVirtioCapBar; 1016 1164 pVirtio->virtioCallbacks.pfnVirtioDevCapRead = devCapReadCallback; 1017 1165 pVirtio->virtioCallbacks.pfnVirtioDevCapWrite = devCapWriteCallback; … … 1029 1177 PCIDevSetInterruptPin (&pVirtio->dev, pPciParams->uInterruptPin); 1030 1178 1031 int rc = VINF_SUCCESS;1032 1179 /* Register PCI device */ 1033 1180 rc = PDMDevHlpPCIRegister(pDevIns, &pVirtio->dev); 1034 1181 if (RT_FAILURE(rc)) 1182 { 1183 RTMemFree(pVirtio); 1035 1184 return PDMDEV_SET_ERROR(pDevIns, rc, 1036 1185 N_("virtio: cannot register PCI Device")); /* can we put params in this error? */ 1186 } 1037 1187 1038 1188 pVirtio->IBase = pDevIns->IBase; 1039 1040 1189 1041 1190 PDMDevHlpPCISetConfigCallbacks(pDevIns, &pVirtio->dev, … … 1050 1199 uint8_t fMsiSupport = false; 1051 1200 #endif 1052 1053 1201 1054 1202 /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T) … … 1068 1216 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1069 1217 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1070 pCfg->uBar = uVirtioCap Region;1218 pCfg->uBar = uVirtioCapBar; 1071 1219 pCfg->uOffset = 0; 1072 1220 pCfg->uLength = sizeof(VIRTIO_PCI_COMMON_CFG_T); … … 1079 1227 pCfg->uCapLen = sizeof(VIRTIO_PCI_NOTIFY_CAP_T); 1080 1228 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1081 pCfg->uBar = uVirtioCap Region;1229 pCfg->uBar = uVirtioCapBar; 1082 1230 pCfg->uOffset = pVirtio->pCommonCfgCap->uOffset + pVirtio->pCommonCfgCap->uLength; 1083 1231 pCfg->uLength = 4; /* This needs to be calculated differently */ … … 1091 1239 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1092 1240 pCfg->uCapNext = CFGADDR2IDX(pCfg) + pCfg->uCapLen; 1093 pCfg->uBar = uVirtioCap Region;1241 pCfg->uBar = uVirtioCapBar; 1094 1242 pCfg->uOffset = pVirtio->pNotifyCap->pciCap.uOffset + pVirtio->pNotifyCap->pciCap.uLength; 1095 1243 pCfg->uLength = sizeof(uint32_t); … … 1101 1249 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR; 1102 1250 pCfg->uCapLen = sizeof(VIRTIO_PCI_CFG_CAP_T); 1103 pCfg->uCapNext = (fMsiSupport || pVirtio-> fHaveDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;1104 pCfg->uBar = uVirtioCap Region;1251 pCfg->uCapNext = (fMsiSupport || pVirtio->pDevSpecificCap) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1252 pCfg->uBar = uVirtioCapBar; 1105 1253 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength; 1106 1254 pCfg->uLength = 4; /* Initialize a non-zero 4-byte aligned so Linux virtio_pci module recognizes this cap */ 1107 1255 pVirtio->pPciCfgCap = (PVIRTIO_PCI_CFG_CAP_T)pCfg; 1108 1256 1109 if (pVirtio-> fHaveDevSpecificCap)1257 if (pVirtio->pDevSpecificCap) 1110 1258 { 1111 1259 /* Following capability mapped via VirtIO 1.0: struct virtio_pci_dev_cap (VIRTIODEVCAP)*/ … … 1115 1263 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1116 1264 pCfg->uCapNext = fMsiSupport ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1117 pCfg->uBar = uVirtioCap Region;1265 pCfg->uBar = uVirtioCapBar; 1118 1266 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength; 1119 1267 pCfg->uLength = cbDevSpecificCap; … … 1139 1287 } 1140 1288 1141 rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCap Region, 4096,1289 rc = PDMDevHlpPCIIORegionRegister(pDevIns, uVirtioCapBar, 4096, 1142 1290 PCI_ADDRESS_SPACE_MEM, virtioR3Map); 1143 1291 if (RT_FAILURE(rc)) 1292 { 1293 RTMemFree(pVirtio->pPrevDevSpecificCap); 1294 RTMemFree(pVirtio); 1144 1295 return PDMDEV_SET_ERROR(pDevIns, rc, 1145 1296 N_("virtio: cannot register PCI Capabilities address space")); 1146 1297 } 1298 *phVirtio = (PVIRTIOHANDLE)pVirtio; 1147 1299 return rc; 1148 1300 } 1149 1150 1301 #endif /* IN_RING3 */ 1151 1302 -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80169 r80194 1 1 /* $Id$ */ 2 2 /** @file 3 * Virtio_1_0 p.h - Virtio Declarations3 * Virtio_1_0.h - Virtio Declarations 4 4 */ 5 5 … … 24 24 #include <iprt/ctype.h> 25 25 26 /** @name Saved state versions. 27 * The saved state version is changed if either common or any of specific 28 * parts are changed. That is, it is perfectly possible that the version 29 * of saved vnet state will increase as a result of change in vblk structure 30 * for example. 31 */ 32 #define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1 33 #define VIRTIO_SAVEDSTATE_VERSION 2 34 /** @} */ 26 #define VIRTQ_MAX_SIZE 1024 27 #define VIRTIO_MAX_QUEUES 256 /** Max queues we allow guest to create */ 28 #define VIRTQ_DESC_MAX_SIZE (2 * 1024 * 1024) 29 30 typedef void * VIRTIOHANDLE; /** opaque handle to the VirtIO framework */ 31 typedef VIRTIOHANDLE *PVIRTIOHANDLE; 35 32 36 33 /** Reserved Feature Bits */ … … 39 36 #define VIRTIO_F_VERSION_1 RT_BIT_64(32) 40 37 41 #define MAX_QUEUES 5 /** Maximum number of queues we support */ 42 43 /** Mandatory for Virtio PCI device identification, per spec */ 44 #define DEVICE_PCI_VENDOR_ID_VIRTIO 0x1AF4 45 46 /** Virtio spec suggests >= 1 for non-transitional drivers */ 47 #define DEVICE_PCI_REVISION_ID_VIRTIO 1 48 49 /* Virtio Device PCI Capabilities type codes */ 50 #define VIRTIO_PCI_CAP_COMMON_CFG 1 51 #define VIRTIO_PCI_CAP_NOTIFY_CFG 2 52 #define VIRTIO_PCI_CAP_ISR_CFG 3 53 #define VIRTIO_PCI_CAP_DEVICE_CFG 4 54 #define VIRTIO_PCI_CAP_PCI_CFG 5 38 #define VIRTIO_MSI_NO_VECTOR 0xffff /* Vector value used to disable MSI for queue */ 55 39 56 40 /** Device Status field constants (from Virtio 1.0 spec) */ … … 62 46 #define VIRTIO_STATUS_DEVICE_NEEDS_RESET 0x40 /** Device experienced unrecoverable error */ 63 47 64 #define VIRTIO_MAX_NQUEUES 256 /** Max queues we allow guest to create */ 65 #define VIRTQUEUEDESC_MAX_SIZE (2 * 1024 * 1024) /** Legacy only? */ 66 #define VIRTQUEUE_MAX_SIZE 1024 /** According to? Legacy only? */ 67 #define VIRTIO_ISR_QUEUE 0x1 /* Legacy only? Now derived from feature negotiation? */ 68 #define VIRTIO_ISR_CONFIG 0x3 /* Legacy only? Now derived from feature negotiation? */ 69 70 #define VIRTIO_PCI_CAP_ID_VENDOR 0x09 71 72 /* Vector value used to disable MSI for queue */ 73 #define VIRTIO_MSI_NO_VECTOR 0xffff 74 75 /** Most of the following definitions attempt to adhere to the names and 76 * and forms used by the VirtIO 1.0 specification to increase the maintainability 77 * and speed of ramp-up, in other words, to as unambiguously as possible 78 * map the spec to the VirtualBox implementation of it */ 79 80 /** Indicates that this descriptor chains to another */ 81 #define VIRTQ_DESC_F_NEXT 1 82 83 /** Marks buffer as write-only (default ro) */ 84 #define VIRTQ_DESC_F_WRITE 2 85 86 /** This means the buffer contains a list of buffer descriptors. */ 87 #define VIRTQ_DESC_F_INDIRECT 4 88 89 /** Optimization: Device advises driver (unreliably): Don't kick me when adding buffer */ 90 #define VIRTQ_USED_F_NO_NOTIFY 1 91 92 /** Optimization: Driver advises device (unreliably): Don't interrupt when buffer consumed */ 93 #define VIRTQ_AVAIL_F_NO_INTERRUPT 1 94 95 /** Using indirect descriptors */ 96 #define VIRTIO_F_INDIRECT_DESC 28 97 98 /** Indicates either avail_event, or used_event fields are in play */ 99 #define VIRTIO_F_EVENT_IDX 29 100 101 /** Allow aribtary descriptor layouts */ 102 #define VIRTIO_F_ANY_LAYOUT 27 103 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; 132 133 /** 134 * The following structure is used to pass the PCI parameters from the consumer 135 * to this generic VirtIO framework 136 */ 104 137 typedef struct VIRTIOPCIPARAMS 105 138 { … … 115 148 } VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS; 116 149 117 typedef struct virtio_pci_cap118 {119 /* All little-endian */120 uint8_t uCapVndr; /** Generic PCI field: PCI_CAP_ID_VNDR */121 uint8_t uCapNext; /** Generic PCI field: next ptr. */122 uint8_t uCapLen; /** Generic PCI field: capability length */123 uint8_t uCfgType; /** Identifies the structure. */124 uint8_t uBar; /** Where to find it. */125 uint8_t uPadding[3]; /** Pad to full dword. */126 uint32_t uOffset; /** Offset within bar. (L.E.) */127 uint32_t uLength; /** Length of struct, in bytes. (L.E.) */128 } VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T;129 130 typedef struct virtio_pci_common_cfg /* VirtIO 1.0 specification name of this struct */131 {132 /**133 *134 * RW = driver (guest) writes value into this field.135 * RO = device (host) writes value into this field.136 */137 138 /* Per device fields */139 uint32_t uDeviceFeaturesSelect; /** RW (driver selects device features) */140 uint32_t uDeviceFeatures; /** RO (device reports features to driver) */141 uint32_t uDriverFeaturesSelect; /** RW (driver selects driver features) */142 uint32_t uDriverFeatures; /** RW (driver accepts device features) */143 uint16_t uMsixConfig; /** RW (driver sets MSI-X config vector) */144 uint16_t uNumQueues; /** RO (device specifies max queues) */145 uint8_t uDeviceStatus; /** RW (driver writes device status, 0 resets) */146 uint8_t uConfigGeneration; /** RO (device changes when changing configs) */147 148 /* Per virtqueue fields (as determined by uQueueSelect) */149 uint16_t uQueueSelect; /** RW (selects queue focus for these fields) */150 uint16_t uQueueSize; /** RW (queue size, 0 - 2^n) */151 uint16_t uQueueMsixVector; /** RW (driver selects MSI-X queue vector) */152 uint16_t uQueueEnable; /** RW (driver controls usability of queue) */153 uint16_t uQueueNotifyOff; /** RO (offset uto virtqueue; see spec) */154 uint64_t uQueueDesc; /** RW (driver writes desc table phys addr) */155 uint64_t uQueueAvail; /** RW (driver writes avail ring phys addr) */156 uint64_t uQueueUsed; /** RW (driver writes used ring phys addr) */157 } VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T;158 159 /* The following two types are opaque here. The device-specific capabilities are handled160 * through a callback to the consumer host device driver, where the corresponding161 * struct is declared, since it cannot be defined in the host-generic section of162 * the VirtIO specification. */163 164 typedef void * PVIRTIO_PCI_DEVICE_CAP_T;165 typedef struct virtio_pci_device_cap166 {167 } VIRTIO_PCI_DEVICE_CAP_T;168 169 typedef struct virtio_pci_notify_cap170 {171 struct virtio_pci_cap pciCap;172 uint32_t uNotifyOffMultiplier; /* notify_off_multiplier */173 } VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T;174 175 /*176 * If the client of this library has any device-specific capabilities, it must define177 * and implement this struct and the macro178 */179 typedef struct virtio_pci_cfg_cap {180 struct virtio_pci_cap pciCap;181 uint8_t uPciCfgData[4]; /* Data for BAR access. */182 } VIRTIO_PCI_CFG_CAP_T, *PVIRTIO_PCI_CFG_CAP_T;183 184 typedef struct virtq_desc /* VirtIO 1.0 specification formal name of this struct */185 {186 uint64_t pGcPhysBuf; /** addr GC physical address of buffer */187 uint32_t cbBuf; /** len Buffer length */188 uint16_t fFlags; /** flags Buffer specific flags */189 uint16_t uNext; /** next Chain idx if VIRTIO_DESC_F_NEXT */190 } VIRTQUEUEDESC, *PVIRTQUEUEDESC;191 192 typedef struct virtq_avail /* VirtIO 1.0 specification formal name of this struct */193 {194 uint16_t fFlags; /** flags avail ring guest-to-host flags */195 uint16_t uIdx; /** idx Index of next free ring slot */196 uint16_t auRing[1]; /** ring Ring: avail guest-to-host bufs */197 uint16_t uUsedEventIdx; /** used_event (if VIRTQ_USED_F_NO_NOTIFY) */198 } VIRTQUEUEAVAIL, *PVIRTQUEUEAVAIL;199 200 typedef struct virtq_used_elem /* VirtIO 1.0 specification formal name of this struct */201 {202 uint32_t uIdx; /** idx Start of used descriptor chain */203 uint32_t cbElem; /** len Total len of used desc chain */204 } VIRTQUEUEUSEDELEM;205 206 typedef struct virt_used /* VirtIO 1.0 specification formal name of this struct */207 {208 uint16_t fFlags; /** flags used ring host-to-guest flags */209 uint16_t uIdx; /** idx Index of next ring slot */210 VIRTQUEUEUSEDELEM aRing[1]; /** ring Ring: used host-to-guest bufs */211 uint16_t uAvailEventIdx; /** avail_event if (VIRTQ_USED_F_NO_NOTIFY) */212 } VIRTQUEUEUSED, *PVIRTQUEUEUSED;213 214 215 typedef struct virtq216 {217 uint16_t cbQueue; /** virtq size */218 uint16_t padding[3]; /** 64-bit-align phys ptrs to start of struct */219 RTGCPHYS pGcPhysVirtqDescriptors; /** (struct virtq_desc *) */220 RTGCPHYS pGcPhysVirtqAvail; /** (struct virtq_avail *) */221 RTGCPHYS pGcPhysVirtqUsed; /** (struct virtq_used *) */222 } VIRTQUEUE, *PVIRTQUEUE;223 224 /**225 * Queue callback (consumer?).226 *227 * @param pvState Pointer to the VirtIO PCI core state, VIRTIOSTATE.228 * @param pQueue Pointer to the queue structure.229 */230 typedef DECLCALLBACK(void) FNVIRTIOQUEUECALLBACK(void *pvState, struct VQueue *pQueue);231 /** Pointer to a VQUEUE callback function. */232 typedef FNVIRTIOQUEUECALLBACK *PFNVIRTIOQUEUECALLBACK;233 234 //PCIDevGetCapabilityList235 //PCIDevSetCapabilityList236 //DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset)237 // PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset);238 //DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PPDMPCIDEV pPciDev)239 // return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST);240 241 typedef struct VQueue242 {243 VIRTQUEUE VirtQueue;244 uint16_t uNextAvailIndex;245 uint16_t uNextUsedIndex;246 uint32_t uPageNumber;247 R3PTRTYPE(PFNVIRTIOQUEUECALLBACK) pfnCallback;248 R3PTRTYPE(const char *) pcszName;249 } VQUEUE;250 typedef VQUEUE *PVQUEUE;251 252 typedef struct VQueueElemSeg253 {254 RTGCPHYS addr;255 void *pv;256 uint32_t cb;257 } VQUEUESEG;258 259 typedef struct VQueueElem260 {261 uint32_t idx;262 uint32_t nIn;263 uint32_t nOut;264 VQUEUESEG aSegsIn[VIRTQUEUE_MAX_SIZE];265 VQUEUESEG aSegsOut[VIRTQUEUE_MAX_SIZE];266 } VQUEUEELEM;267 typedef VQUEUEELEM *PVQUEUEELEM;268 269 270 /**271 * Interface this library uses to let the client handle VirtioIO device-specific capabilities I/O272 */273 274 150 /** 275 151 * VirtIO Device-specific capabilities read callback … … 304 180 DECLCALLBACKMEMBER(int, pfnVirtioDevCapWrite) 305 181 (PPDMDEVINS pDevIns, uint32_t uOffset, const void *pvBuf, size_t cbWrite); 306 } VIRTIOCALLBACKS, *PVIRT ALCALLBACKS;182 } VIRTIOCALLBACKS, *PVIRTIOCALLBACKS; 307 183 /** @} */ 308 184 309 /** 310 * The core (/common) state of the VirtIO PCI device 311 * 312 * @implements PDMILEDPORTS 313 */ 314 typedef struct VIRTIOSTATE 315 { 316 PDMPCIDEV dev; 317 PDMCRITSECT cs; /**< Critical section - what is it protecting? */ 318 /* Read-only part, never changes after initialization. */ 319 char szInstance[8]; /**< Instance name, e.g. VNet#1. */ 320 321 #if HC_ARCH_BITS != 64 322 uint32_t padding1; 323 #endif 324 325 /** Status LUN: Base interface. */ 326 PDMIBASE IBase; 327 328 /** Status LUN: LED port interface. */ 329 PDMILEDPORTS ILed; 330 331 /* Read/write part, protected with critical section. */ 332 /** Status LED. */ 333 PDMLED led; 334 335 VIRTIOCALLBACKS virtioCallbacks; 336 337 /** Status LUN: LED connector (peer). */ 338 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector; 339 340 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3. */ 341 PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0. */ 342 PPDMDEVINSRC pDevInsRC; /**< Device instance - RC. */ 343 344 345 uint8_t uPciCfgDataOff; 346 #if HC_ARCH_BITS == 64 347 uint32_t padding2; 348 #endif 349 350 /** Base port of I/O space region. */ 351 RTIOPORT IOPortBase; 352 353 uint32_t uGuestFeatures; 354 uint16_t uQueueSelector; /** An index in aQueues array. */ 355 uint8_t uStatus; /** Device Status (bits are device-specific). */ 356 uint8_t uISR; /** Interrupt Status Register. */ 357 358 #if HC_ARCH_BITS != 64 359 uint32_t padding3; 360 #endif 361 362 uint32_t nQueues; /** Actual number of queues used. */ 363 VQUEUE Queues[VIRTIO_MAX_NQUEUES]; 364 365 uint32_t uDeviceFeaturesSelect; /** Select hi/lo 32-bit uDeviceFeatures to r/w */ 366 uint64_t uDeviceFeatures; /** Host features offered */ 367 uint32_t uDriverFeaturesSelect; /** Selects hi/lo 32-bit uDriverFeatures to r/w*/ 368 uint64_t uDriverFeatures; /** Host features accepted by guest */ 369 370 uint32_t uMsixConfig; 371 uint8_t uDeviceStatus; 372 uint8_t uConfigGeneration; 373 uint32_t uNotifyOffMultiplier; /* Multiplier for uQueueNotifyOff[idx] */ 374 375 uint16_t uQueueSelect; 376 uint16_t uQueueSize[MAX_QUEUES]; 377 uint16_t uQueueMsixVector[MAX_QUEUES]; 378 uint16_t uQueueEnable[MAX_QUEUES]; 379 uint16_t uQueueNotifyOff[MAX_QUEUES]; 380 uint64_t uQueueDesc[MAX_QUEUES]; 381 uint64_t uQueueAvail[MAX_QUEUES]; 382 uint64_t uQueueUsed[MAX_QUEUES]; 383 384 385 uint8_t uVirtioCapRegion; /* Client assigned Virtio dedicated capabilities region*/ 386 387 /** Callbacks when guest driver reads or writes VirtIO device-specific capabilities(s) */ 388 PFNPCICONFIGREAD pfnPciConfigReadOld; 389 PFNPCICONFIGWRITE pfnPciConfigWriteOld; 390 391 bool fHaveDevSpecificCap; 392 uint32_t cbDevSpecificCap; 393 394 PVIRTIO_PCI_CFG_CAP_T pPciCfgCap; /** Pointer to struct in configuration area */ 395 PVIRTIO_PCI_NOTIFY_CAP_T pNotifyCap; /** Pointer to struct in configuration area */ 396 PVIRTIO_PCI_CAP_T pCommonCfgCap; /** Pointer to struct in configuration area */ 397 PVIRTIO_PCI_CAP_T pIsrCap; /** Pointer to struct in configuration area */ 398 PVIRTIO_PCI_CAP_T pDeviceCap; /** Pointer to struct in configuration area */ 399 400 /** Base address of PCI capabilities */ 401 RTGCPHYS GCPhysPciCapBase; 402 RTGCPHYS pGcPhysCommonCfg; /** Pointer to MMIO mapped capability data */ 403 RTGCPHYS pGcPhysNotifyCap; /** Pointer to MMIO mapped capability data */ 404 RTGCPHYS pGcPhysIsrCap; /** Pointer to MMIO mapped capability data */ 405 RTGCPHYS pGcPhysDeviceCap; /** Pointer to MMIO mapped capability data */ 406 407 bool fDeviceConfigInterrupt; 408 bool fQueueInterrupt; 409 410 } VIRTIOSTATE, *PVIRTIOSTATE; 411 412 void virtioRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta); 413 void *virtioQueryInterface(struct PDMIBASE *pInterface, const char *pszIID); 414 415 int virtioConstruct(PPDMDEVINS pDevIns, PVIRTIOSTATE pVirtio, int iInstance, PVIRTIOPCIPARAMS pPciParams, 416 const char *pcszNameFmt, uint32_t nQueues, uint32_t uVirtioCapRegion, 417 PFNVIRTIODEVCAPREAD devCapReadCallback, PFNVIRTIODEVCAPWRITE devCapWriteCallback, 418 uint16_t cbDevSpecificCap, bool fHaveDevSpecificCap, uint32_t uNotifyOffMultiplier); 419 420 int virtioDestruct(PVIRTIOSTATE pVirtio); 421 int virtioReset(PVIRTIOSTATE pVirtio); 422 int virtioSaveExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM); 423 int virtioLoadExec(PVIRTIOSTATE pVirtio, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, uint32_t nQueues); 424 void virtioSetReadLed(PVIRTIOSTATE pVirtio, bool fOn); 425 void virtioSetWriteLed(PVIRTIOSTATE pVirtio, bool fOn); 426 int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, int rcBusy, uint8_t uint8_tIntCause); 427 void virtioNotify(PVIRTIOSTATE pVirtio); 428 void virtioSetHostFeatures(PVIRTIOSTATE pVirtio, uint64_t uDeviceFeatures); 429 430 PVQUEUE virtioAddQueue(PVIRTIOSTATE pVirtio, unsigned uSize, PFNVIRTIOQUEUECALLBACK pfnCallback, const char *pcszName); 431 bool virtQueueSkip(PVIRTIOSTATE pVirtio, PVQUEUE pQueue); 432 bool virtQueueGet(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemove = true); 433 void virtQueuePut(PVIRTIOSTATE pVirtio, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t len, uint32_t uReserved = 0); 434 void virtQueueNotify(PVIRTIOSTATE pVirtio, PVQUEUE pQueue); 435 void virtQueueSync(PVIRTIOSTATE pVirtio, PVQUEUE pQueue); 436 void vringSetNotification( PVIRTIOSTATE pVirtio, PVIRTQUEUE pVirtQueue, bool fEnabled); 437 438 439 /* FROM Virtio 1.0 SPEC, NYI 440 static inline int virtq_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old_idx) 441 return (uint16_t)(new_idx - event_idx - 1) < (uint16_t)(new_idx - old_idx); 442 } 443 // Get location of event indices (only with VIRTIO_F_EVENT_IDX) 444 static inline le16 *virtq_used_event(struct virtq *vq) 445 { 446 // For backwards compat, used event index is at *end* of avail ring. 447 return &vq->avail->ring[vq->num]; 448 } 449 static inline le16 *virtq_avail_event(struct virtq *vq) 450 { 451 // For backwards compat, avail event index is at *end* of used ring. 452 return (le16 *)&vq->used->ring[vq->num]; 453 } 454 } 455 */ 456 457 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); 458 200 459 201 /** … … 469 211 * @param idx - The index if fHasIndex 470 212 */ 471 DECLINLINE(void) virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, const void *pv, uint32_t cb, 472 uint32_t uOffset, bool fWrite, bool fHasIndex, uint32_t idx) 473 { 474 475 #define FMTHEX(fmtout, v, cNybs) \ 476 fmtout[cNybs] = '\0'; \ 477 for (uint8_t i = 0; i < cNybs; i++) \ 478 fmtout[(cNybs - i) -1] = "0123456789abcdef"[(val >> (i * 4)) & 0xf]; 479 480 #define MAX_STRING 64 481 char pszIdx[MAX_STRING] = { 0 }; 482 char pszDepiction[MAX_STRING] = { 0 }; 483 char pszFormattedVal[MAX_STRING] = { 0 }; 484 if (fHasIndex) 485 RTStrPrintf(pszIdx, sizeof(pszIdx), "[%d]", idx); 486 if (cb == 1 || cb == 2 || cb == 4 || cb == 8) 487 { 488 /* manually padding with 0's instead of \b due to different impl of %x precision than printf() */ 489 uint64_t val = 0; 490 memcpy((char *)&val, pv, cb); 491 FMTHEX(pszFormattedVal, val, cb * 2); 492 if (uOffset != 0) /* display bounds if partial member access */ 493 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s[%d:%d]", pszMember, pszIdx, uOffset, uOffset + cb - 1); 494 else 495 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%s%s", pszMember, pszIdx); 496 RTStrPrintf(pszDepiction, sizeof(pszDepiction), "%-30s", pszDepiction); 497 int first = 0; 498 for (uint8_t i = 0; i < sizeof(pszDepiction); i++) 499 if (pszDepiction[i] == ' ' && first++ != 0) 500 pszDepiction[i] = '.'; 501 Log(("%s: Guest %s %s 0x%s\n", \ 502 pszFunc, fWrite ? "wrote" : "read ", pszDepiction, pszFormattedVal)); 503 } 504 else /* odd number or oversized access, ... log inline hex-dump style */ 505 { 506 Log(("%s: Guest %s %s%s[%d:%d]: %.*Rhxs\n", \ 507 pszFunc, fWrite ? "wrote" : "read ", pszMember, 508 pszIdx, uOffset, uOffset + cb, cb, pv)); 509 } 510 } 511 512 typedef DECLCALLBACK(uint32_t) FNGETHOSTFEATURES(void *pvState); 513 typedef FNGETHOSTFEATURES *PFNGETHOSTFEATURES; 514 515 DECLINLINE(uint16_t) vringReadAvail(PVIRTIOSTATE pState, PVIRTQUEUE pVirtQueue) 516 { 517 uint16_t dataWord; 518 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns), 519 pVirtQueue->pGcPhysVirtqAvail + RT_UOFFSETOF(VIRTQUEUEAVAIL, uIdx), 520 &dataWord, sizeof(dataWord)); 521 return dataWord; 522 } 523 524 DECLINLINE(bool) virtQueuePeek(PVIRTIOSTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem) 525 { 526 return virtQueueGet(pState, pQueue, pElem, /* fRemove */ false); 527 } 528 529 DECLINLINE(bool) virtQueueIsReady(PVIRTIOSTATE pState, PVQUEUE pQueue) 530 { 531 NOREF(pState); 532 return !!pQueue->VirtQueue.pGcPhysVirtqAvail; 533 } 534 535 DECLINLINE(bool) virtQueueIsEmpty(PVIRTIOSTATE pState, PVQUEUE pQueue) 536 { 537 return (vringReadAvail(pState, &pQueue->VirtQueue) == pQueue->uNextAvailIndex); 538 } 213 void virtioLogMappedIoValue(const char *pszFunc, const char *pszMember, 214 const void *pv, uint32_t cb, uint32_t uOffset, 215 bool fWrite, bool fHasIndex, uint32_t idx); 216 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); 539 238 540 239 #endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_h */ -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r80169 r80194 22 22 #endif 23 23 24 #include "Virtio_1_0.h" 25 26 27 28 /** @name Saved state versions. 29 * The saved state version is changed if either common or any of specific 30 * parts are changed. That is, it is perfectly possible that the version 31 * of saved vnet state will increase as a result of change in vblk structure 32 * for example. 33 */ 34 #define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1 35 #define VIRTIO_SAVEDSTATE_VERSION 2 36 /** @} */ 37 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 41 42 /** 43 * The following is the PCI capability struct common to all VirtIO capability types 44 */ 45 #define VIRTIO_PCI_CAP_ID_VENDOR 0x09 /** Vendor-specific PCI CFG Device Capability ID */ 46 47 typedef struct virtio_pci_cap 48 { 49 /* 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.) */ 58 } VIRTIO_PCI_CAP_T, *PVIRTIO_PCI_CAP_T; 59 60 /** 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 65 * 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 */ 76 { 77 /* 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) */ 86 87 /* 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) */ 96 } VIRTIO_PCI_COMMON_CFG_T, *PVIRTIO_PCI_COMMON_CFG_T; 97 98 typedef struct virtio_pci_notify_cap 99 { 100 struct virtio_pci_cap pciCap; 101 uint32_t uNotifyOffMultiplier; /* notify_off_multiplier */ 102 } VIRTIO_PCI_NOTIFY_CAP_T, *PVIRTIO_PCI_NOTIFY_CAP_T; 103 104 typedef struct virtio_pci_cfg_cap 105 { 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; 109 110 /** 111 * The core (/common) state of the VirtIO PCI device 112 * 113 * @implements PDMILEDPORTS 114 */ 115 typedef struct VIRTIOSTATE 116 { 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; 213 214 } VIRTIOSTATE, *PVIRTIOSTATE; 215 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 } 24 240 /** 25 241 * This macro returns true if physical address and access length are within the mapped capability struct. … … 146 362 } 147 363 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); 385 148 386 #endif /* !VBOX_INCLUDED_SRC_VirtIO_Virtio_1_0_impl_h */
Note:
See TracChangeset
for help on using the changeset viewer.