- Timestamp:
- Nov 20, 2009 8:51:12 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/log.h
r22866 r24834 138 138 /** VGA Device group. */ 139 139 LOG_GROUP_DEV_VGA, 140 /** Virtio PCI Device group. */ 141 LOG_GROUP_DEV_VIRTIO, 140 142 /** Virtio Network Device group. */ 141 143 LOG_GROUP_DEV_VIRTIO_NET, … … 388 390 "DEV_USB", \ 389 391 "DEV_VGA", \ 392 "DEV_VIRTIO", \ 390 393 "DEV_VIRTIO_NET", \ 391 394 "DEV_VMM", \ -
trunk/src/VBox/Devices/Makefile.kmk
r24706 r24834 318 318 DevicesR3_DEFS += VBOX_WITH_VIRTIO 319 319 DevicesR3_SOURCES += \ 320 Virtio.cpp \ 320 321 Network/DevVirtioNet.cpp 321 322 endif … … 515 516 VBoxDDGC_DEFS += VBOX_WITH_VIRTIO 516 517 VBoxDDGC_SOURCES += \ 518 Virtio.cpp \ 517 519 Network/DevVirtioNet.cpp 518 520 endif … … 612 614 VBoxDDR0_DEFS += VBOX_WITH_VIRTIO 613 615 VBoxDDR0_SOURCES += \ 616 Virtio.cpp \ 614 617 Network/DevVirtioNet.cpp 615 618 endif -
trunk/src/VBox/Devices/Network/DevVirtioNet.cpp
r24757 r24834 25 25 #define VNET_GC_SUPPORT 26 26 27 #include <iprt/ctype.h> 27 #include <VBox/pdmdev.h> 28 #include <iprt/semaphore.h> 28 29 #ifdef IN_RING3 29 30 # include <iprt/mem.h> 30 31 #endif /* IN_RING3 */ 31 #include <iprt/param.h>32 #include <iprt/semaphore.h>33 #include <VBox/pdmdev.h>34 #include <VBox/tm.h>35 32 #include "../Builtins.h" 33 #include "Virtio.h" 34 35 36 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 37 38 #define INSTANCE(pState) pState->VPCI.szInstance 39 #define IFACE_TO_STATE(pIface, ifaceName) \ 40 ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName))) 41 #define STATUS pState->config.uStatus 42 43 #ifdef IN_RING3 44 45 #define VNET_PCI_SUBSYSTEM_ID 1 + VIRTIO_NET_ID 46 #define VNET_PCI_CLASS 0x0200 47 #define VNET_N_QUEUES 3 48 #define VNET_NAME_FMT "VNet%d" 49 36 50 #if 0 37 #include <iprt/crc32.h> 38 #include <iprt/string.h> 39 #include <VBox/vm.h> 51 /* Virtio Block Device */ 52 #define VNET_PCI_SUBSYSTEM_ID 1 + VIRTIO_BLK_ID 53 #define VNET_PCI_CLASS 0x0180 54 #define VNET_N_QUEUES 2 55 #define VNET_NAME_FMT "VBlk%d" 40 56 #endif 41 57 42 // TODO: move declarations to the header file: #include "DevVirtioNet.h" 43 44 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 45 46 #define INSTANCE(pState) pState->szInstance 47 #define IFACE_TO_STATE(pIface, ifaceName) ((VPCISTATE *)((char*)pIface - RT_OFFSETOF(VPCISTATE, ifaceName))) 48 49 #define VIRTIO_RELOCATE(p, o) *(RTHCUINTPTR *)&p += o 50 51 #ifdef DEBUG 52 #define QUEUENAME(s, q) (q->pcszName) 53 #endif /* DEBUG */ 54 55 #endif /* VBOX_DEVICE_STRUCT_TESTCASE */ 56 57 //- TODO: Move to Virtio.h ---------------------------------------------------- 58 59 /* 60 * The saved state version is changed if either common or any of specific 61 * parts are changed. That is, it is perfectly possible that the version 62 * of saved vnet state will increase as a result of change in vblk structure 63 * for example. 64 */ 65 #define VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1 1 66 #define VIRTIO_SAVEDSTATE_VERSION 2 67 68 #define VPCI_F_NOTIFY_ON_EMPTY 0x01000000 69 #define VPCI_F_BAD_FEATURE 0x40000000 70 71 #define VRINGDESC_MAX_SIZE (2 * 1024 * 1024) 72 #define VRINGDESC_F_NEXT 0x01 73 #define VRINGDESC_F_WRITE 0x02 74 75 struct VRingDesc 76 { 77 uint64_t u64Addr; 78 uint32_t uLen; 79 uint16_t u16Flags; 80 uint16_t u16Next; 81 }; 82 typedef struct VRingDesc VRINGDESC; 83 typedef VRINGDESC *PVRINGDESC; 84 85 #define VRINGAVAIL_F_NO_INTERRUPT 0x01 86 87 struct VRingAvail 88 { 89 uint16_t uFlags; 90 uint16_t uNextFreeIndex; 91 uint16_t auRing[1]; 92 }; 93 typedef struct VRingAvail VRINGAVAIL; 94 95 struct VRingUsedElem 96 { 97 uint32_t uId; 98 uint32_t uLen; 99 }; 100 typedef struct VRingUsedElem VRINGUSEDELEM; 101 102 #define VRINGUSED_F_NO_NOTIFY 0x01 103 104 struct VRingUsed 105 { 106 uint16_t uFlags; 107 uint16_t uIndex; 108 VRINGUSEDELEM aRing[1]; 109 }; 110 typedef struct VRingUsed VRINGUSED; 111 typedef VRINGUSED *PVRINGUSED; 112 113 #define VRING_MAX_SIZE 1024 114 115 struct VRing 116 { 117 uint16_t uSize; 118 uint16_t padding[3]; 119 RTGCPHYS addrDescriptors; 120 RTGCPHYS addrAvail; 121 RTGCPHYS addrUsed; 122 }; 123 typedef struct VRing VRING; 124 typedef VRING *PVRING; 125 126 struct VQueue 127 { 128 VRING VRing; 129 uint16_t uNextAvailIndex; 130 uint16_t uNextUsedIndex; 131 uint32_t uPageNumber; 132 #ifdef IN_RING3 133 void (*pfnCallback)(void *pvState, struct VQueue *pQueue); 134 #else 135 RTR3UINTPTR pfnCallback; 136 #endif 137 R3PTRTYPE(const char *) pcszName; 138 }; 139 typedef struct VQueue VQUEUE; 140 typedef VQUEUE *PVQUEUE; 141 142 struct VQueueElemSeg 143 { 144 RTGCPHYS addr; 145 void *pv; 146 uint32_t cb; 147 }; 148 typedef struct VQueueElemSeg VQUEUESEG; 149 150 struct VQueueElem 151 { 152 uint32_t uIndex; 153 uint32_t nIn; 154 uint32_t nOut; 155 VQUEUESEG aSegsIn[VRING_MAX_SIZE]; 156 VQUEUESEG aSegsOut[VRING_MAX_SIZE]; 157 }; 158 typedef struct VQueueElem VQUEUEELEM; 159 typedef VQUEUEELEM *PVQUEUEELEM; 160 161 162 enum VirtioDeviceType 163 { 164 VIRTIO_NET_ID = 0, 165 VIRTIO_BLK_ID = 1, 166 VIRTIO_32BIT_HACK = 0x7fffffff 167 }; 168 169 #define VIRTIO_MAX_NQUEUES 3 170 #define VNET_NQUEUES 3 171 172 struct VPCIState_st 173 { 174 PDMCRITSECT cs; /**< Critical section - what is it protecting? */ 175 /* Read-only part, never changes after initialization. */ 176 #if HC_ARCH_BITS == 64 177 uint32_t padding1; 178 #endif 179 VirtioDeviceType enmDevType; /**< Device type: net or blk. */ 180 char szInstance[8]; /**< Instance name, e.g. VNet#1. */ 181 182 PDMIBASE IBase; 183 PDMILEDPORTS ILeds; /**< LED interface */ 184 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector; 185 186 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3. */ 187 PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0. */ 188 PPDMDEVINSRC pDevInsRC; /**< Device instance - RC. */ 189 190 #if HC_ARCH_BITS == 64 191 uint32_t padding2; 192 #endif 193 194 /** TODO */ 195 PCIDEVICE pciDevice; 196 /** Base port of I/O space region. */ 197 RTIOPORT addrIOPort; 198 199 /* Read/write part, protected with critical section. */ 200 /** Status LED. */ 201 PDMLED led; 202 203 uint32_t uGuestFeatures; 204 uint16_t uQueueSelector; /**< An index in aQueues array. */ 205 uint8_t uStatus; /**< Device Status (bits are device-specific). */ 206 uint8_t uISR; /**< Interrupt Status Register. */ 207 208 #if HC_ARCH_BITS != 64 209 uint32_t padding3; 210 #endif 211 212 uint32_t nQueues; /**< Actual number of queues used. */ 213 VQUEUE Queues[VIRTIO_MAX_NQUEUES]; 214 215 #if defined(VBOX_WITH_STATISTICS) 216 STAMPROFILEADV StatIOReadGC; 217 STAMPROFILEADV StatIOReadHC; 218 STAMPROFILEADV StatIOWriteGC; 219 STAMPROFILEADV StatIOWriteHC; 220 STAMCOUNTER StatIntsRaised; 221 STAMCOUNTER StatIntsSkipped; 222 #endif /* VBOX_WITH_STATISTICS */ 223 }; 224 typedef struct VPCIState_st VPCISTATE; 225 typedef VPCISTATE *PVPCISTATE; 226 227 //- TODO: Move to VirtioPCI.cpp ----------------------------------------------- 228 229 /*****************************************************************************/ 230 #define virtioGetHostFeatures vnetGetHostFeatures 231 #define virtioGetHostMinimalFeatures vnetGetHostMinimalFeatures 232 #define virtioSetHostFeatures vnetSetHostFeatures 233 #define virtioGetConfig vnetGetConfig 234 #define virtioSetConfig vnetSetConfig 235 #define virtioReset vnetReset 236 #define virtioReady vnetReady 237 238 PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pState); 239 PDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pState); 240 PDMBOTHCBDECL(void) vnetSetHostFeatures(void *pState, uint32_t uFeatures); 241 PDMBOTHCBDECL(int) vnetGetConfig(void *pState, uint32_t port, uint32_t cb, void *data); 242 PDMBOTHCBDECL(int) vnetSetConfig(void *pState, uint32_t port, uint32_t cb, void *data); 243 PDMBOTHCBDECL(void) vnetReset(void *pState); 244 PDMBOTHCBDECL(void) vnetReady(void *pState); 245 246 /*****************************************************************************/ 247 248 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 249 250 #ifdef IN_RING3 251 252 #define DEVICE_PCI_VENDOR_ID 0x1AF4 253 #define DEVICE_PCI_DEVICE_ID 0x1000 254 #define DEVICE_PCI_SUBSYSTEM_VENDOR_ID 0x1AF4 255 #define DEVICE_PCI_SUBSYSTEM_ID 1 + VIRTIO_NET_ID 256 #define DEVICE_PCI_CLASS 0x0200 257 #define DEVICE_N_QUEUES 3 258 #define DEVICE_NAME "virtio-net" 259 #define DEVICE_NAME_FMT "vnet%d" 260 #if 0 261 { /* Virtio Block Device */ 262 0x1AF4, 0x1001, 0x1AF4, 1 + VIRTIO_BLK_ID, 0x0180, 2, "virtio-blk", "vblk%d", 263 NULL, NULL, NULL, NULL, NULL, NULL, NULL 264 }, 265 #endif 266 267 #endif 268 269 #endif /* VBOX_DEVICE_STRUCT_TESTCASE */ 270 271 /*****************************************************************************/ 272 273 #define VPCI_HOST_FEATURES 0x0 274 #define VPCI_GUEST_FEATURES 0x4 275 #define VPCI_QUEUE_PFN 0x8 276 #define VPCI_QUEUE_NUM 0xC 277 #define VPCI_QUEUE_SEL 0xE 278 #define VPCI_QUEUE_NOTIFY 0x10 279 #define VPCI_STATUS 0x12 280 #define VPCI_ISR 0x13 281 #define VPCI_ISR_QUEUE 0x1 282 #define VPCI_ISR_CONFIG 0x3 283 #define VPCI_CONFIG 0x14 284 285 #define VPCI_STATUS_ACK 0x01 286 #define VPCI_STATUS_DRV 0x02 287 #define VPCI_STATUS_DRV_OK 0x04 288 #define VPCI_STATUS_FAILED 0x80 289 290 #ifndef VBOX_DEVICE_STRUCT_TESTCASE 58 #endif /* IN_RING3 */ 291 59 292 60 /* Forward declarations ******************************************************/ 293 61 RT_C_DECLS_BEGIN 294 PDMBOTHCBDECL(int) vpciIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb); 295 PDMBOTHCBDECL(int) vpciIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb); 296 PDMBOTHCBDECL(int) vpciRaiseInterrupt(VPCISTATE *pState, int rcBusy, uint8_t u8IntCause); 62 PDMBOTHCBDECL(int) vnetIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb); 63 PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb); 297 64 RT_C_DECLS_END 298 65 299 300 static void vqueueReset(PVQUEUE pQueue)301 {302 pQueue->VRing.addrDescriptors = 0;303 pQueue->VRing.addrAvail = 0;304 pQueue->VRing.addrUsed = 0;305 pQueue->uNextAvailIndex = 0;306 pQueue->uNextUsedIndex = 0;307 pQueue->uPageNumber = 0;308 }309 310 static void vqueueInit(PVQUEUE pQueue, uint32_t uPageNumber)311 {312 pQueue->VRing.addrDescriptors = uPageNumber << PAGE_SHIFT;313 pQueue->VRing.addrAvail = pQueue->VRing.addrDescriptors314 + sizeof(VRINGDESC) * pQueue->VRing.uSize;315 pQueue->VRing.addrUsed = RT_ALIGN(316 pQueue->VRing.addrAvail + RT_OFFSETOF(VRINGAVAIL, auRing[pQueue->VRing.uSize]),317 PAGE_SIZE); /* The used ring must start from the next page. */318 pQueue->uNextAvailIndex = 0;319 pQueue->uNextUsedIndex = 0;320 }321 322 uint16_t vringReadAvailIndex(PVPCISTATE pState, PVRING pVRing)323 {324 uint16_t tmp;325 326 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),327 pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, uNextFreeIndex),328 &tmp, sizeof(tmp));329 return tmp;330 }331 332 DECLINLINE(bool) vqueueIsReady(PVPCISTATE pState, PVQUEUE pQueue)333 {334 return !!pQueue->VRing.addrAvail;335 }336 337 DECLINLINE(bool) vqueueIsEmpty(PVPCISTATE pState, PVQUEUE pQueue)338 {339 return (vringReadAvailIndex(pState, &pQueue->VRing) == pQueue->uNextAvailIndex);340 }341 342 void vqueueElemFree(PVQUEUEELEM pElem)343 {344 }345 346 void vringReadDesc(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex, PVRINGDESC pDesc)347 {348 //Log(("%s vringReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVRing, uIndex));349 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),350 pVRing->addrDescriptors + sizeof(VRINGDESC) * (uIndex % pVRing->uSize),351 pDesc, sizeof(VRINGDESC));352 }353 354 uint16_t vringReadAvail(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex)355 {356 uint16_t tmp;357 358 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),359 pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, auRing[uIndex % pVRing->uSize]),360 &tmp, sizeof(tmp));361 return tmp;362 }363 364 uint16_t vringReadAvailFlags(PVPCISTATE pState, PVRING pVRing)365 {366 uint16_t tmp;367 368 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),369 pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, uFlags),370 &tmp, sizeof(tmp));371 return tmp;372 }373 374 DECLINLINE(void) vringSetNotification(PVPCISTATE pState, PVRING pVRing, bool fEnabled)375 {376 uint16_t tmp;377 378 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),379 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uFlags),380 &tmp, sizeof(tmp));381 382 if (fEnabled)383 tmp &= ~ VRINGUSED_F_NO_NOTIFY;384 else385 tmp |= VRINGUSED_F_NO_NOTIFY;386 387 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),388 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uFlags),389 &tmp, sizeof(tmp));390 }391 392 bool vqueueGet(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem)393 {394 if (vqueueIsEmpty(pState, pQueue))395 return false;396 397 pElem->nIn = pElem->nOut = 0;398 399 Log2(("%s vqueueGet: %s avail_idx=%u\n", INSTANCE(pState),400 QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex));401 402 VRINGDESC desc;403 uint16_t idx = vringReadAvail(pState, &pQueue->VRing, pQueue->uNextAvailIndex++);404 pElem->uIndex = idx;405 do406 {407 VQUEUESEG *pSeg;408 409 vringReadDesc(pState, &pQueue->VRing, idx, &desc);410 if (desc.u16Flags & VRINGDESC_F_WRITE)411 {412 Log2(("%s vqueueGet: %s IN seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),413 QUEUENAME(pState, pQueue), pElem->nIn, idx, desc.u64Addr, desc.uLen));414 pSeg = &pElem->aSegsIn[pElem->nIn++];415 }416 else417 {418 Log2(("%s vqueueGet: %s OUT seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),419 QUEUENAME(pState, pQueue), pElem->nOut, idx, desc.u64Addr, desc.uLen));420 pSeg = &pElem->aSegsOut[pElem->nOut++];421 }422 423 pSeg->addr = desc.u64Addr;424 pSeg->cb = desc.uLen;425 pSeg->pv = NULL;426 427 idx = desc.u16Next;428 } while (desc.u16Flags & VRINGDESC_F_NEXT);429 430 Log2(("%s vqueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState),431 QUEUENAME(pState, pQueue), pElem->uIndex, pElem->nIn, pElem->nOut));432 return true;433 }434 435 uint16_t vringReadUsedIndex(PVPCISTATE pState, PVRING pVRing)436 {437 uint16_t tmp;438 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),439 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uIndex),440 &tmp, sizeof(tmp));441 return tmp;442 }443 444 void vringWriteUsedIndex(PVPCISTATE pState, PVRING pVRing, uint16_t u16Value)445 {446 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),447 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uIndex),448 &u16Value, sizeof(u16Value));449 }450 451 void vringWriteUsedElem(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex, uint32_t uId, uint32_t uLen)452 {453 VRINGUSEDELEM elem;454 455 elem.uId = uId;456 elem.uLen = uLen;457 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),458 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, aRing[uIndex % pVRing->uSize]),459 &elem, sizeof(elem));460 }461 462 void vqueuePut(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen)463 {464 unsigned int i, uOffset;465 466 Log2(("%s vqueuePut: %s desc_idx=%u acb=%u\n", INSTANCE(pState),467 QUEUENAME(pState, pQueue), pElem->uIndex, uLen));468 for (i = uOffset = 0; i < pElem->nIn && uOffset < uLen; i++)469 {470 uint32_t cbSegLen = RT_MIN(uLen - uOffset, pElem->aSegsIn[i].cb);471 if (pElem->aSegsIn[i].pv)472 {473 Log2(("%s vqueuePut: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", INSTANCE(pState),474 QUEUENAME(pState, pQueue), pQueue->uNextUsedIndex, i, pElem->aSegsIn[i].addr, pElem->aSegsIn[i].pv, pElem->aSegsIn[i].cb, cbSegLen));475 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns), pElem->aSegsIn[i].addr,476 pElem->aSegsIn[i].pv, cbSegLen);477 }478 uOffset += cbSegLen;479 }480 481 Log2(("%s vqueuePut: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n", INSTANCE(pState),482 QUEUENAME(pState, pQueue), pQueue->uNextUsedIndex, vringReadUsedIndex(pState, &pQueue->VRing), pElem->uIndex, uLen));483 vringWriteUsedElem(pState, &pQueue->VRing, pQueue->uNextUsedIndex++, pElem->uIndex, uLen);484 }485 486 void vqueueNotify(PVPCISTATE pState, PVQUEUE pQueue)487 {488 LogFlow(("%s vqueueNotify: %s availFlags=%x guestFeatures=%x vqueue is %sempty\n",489 INSTANCE(pState), QUEUENAME(pState, pQueue),490 vringReadAvailFlags(pState, &pQueue->VRing),491 pState->uGuestFeatures, vqueueIsEmpty(pState, pQueue)?"":"not "));492 if (!(vringReadAvailFlags(pState, &pQueue->VRing) & VRINGAVAIL_F_NO_INTERRUPT)493 || ((pState->uGuestFeatures & VPCI_F_NOTIFY_ON_EMPTY) && vqueueIsEmpty(pState, pQueue)))494 {495 int rc = vpciRaiseInterrupt(pState, VERR_INTERNAL_ERROR, VPCI_ISR_QUEUE);496 if (RT_FAILURE(rc))497 Log(("%s vqueueNotify: Failed to raise an interrupt (%Vrc).\n", INSTANCE(pState), rc));498 }499 else500 {501 STAM_COUNTER_INC(&pState->StatIntsSkipped);502 }503 504 }505 506 void vqueueSync(PVPCISTATE pState, PVQUEUE pQueue)507 {508 Log2(("%s vqueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState),509 QUEUENAME(pState, pQueue), vringReadUsedIndex(pState, &pQueue->VRing), pQueue->uNextUsedIndex));510 vringWriteUsedIndex(pState, &pQueue->VRing, pQueue->uNextUsedIndex);511 vqueueNotify(pState, pQueue);512 }513 514 void vpciReset(PVPCISTATE pState)515 {516 pState->uGuestFeatures = 0;517 pState->uQueueSelector = 0;518 pState->uStatus = 0;519 pState->uISR = 0;520 521 for (unsigned i = 0; i < pState->nQueues; i++)522 vqueueReset(&pState->Queues[i]);523 }524 525 526 DECLINLINE(int) vpciCsEnter(VPCISTATE *pState, int iBusyRc)527 {528 return PDMCritSectEnter(&pState->cs, iBusyRc);529 }530 531 DECLINLINE(void) vpciCsLeave(VPCISTATE *pState)532 {533 PDMCritSectLeave(&pState->cs);534 }535 536 /**537 * Raise interrupt.538 *539 * @param pState The device state structure.540 * @param rcBusy Status code to return when the critical section is busy.541 * @param u8IntCause Interrupt cause bit mask to set in PCI ISR port.542 */543 PDMBOTHCBDECL(int) vpciRaiseInterrupt(VPCISTATE *pState, int rcBusy, uint8_t u8IntCause)544 {545 int rc = vpciCsEnter(pState, rcBusy);546 if (RT_UNLIKELY(rc != VINF_SUCCESS))547 return rc;548 549 STAM_COUNTER_INC(&pState->StatIntsRaised);550 LogFlow(("%s vpciRaiseInterrupt: u8IntCause=%x\n",551 INSTANCE(pState), u8IntCause));552 553 pState->uISR |= u8IntCause;554 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 1);555 vpciCsLeave(pState);556 return VINF_SUCCESS;557 }558 559 /**560 * Lower interrupt.561 *562 * @param pState The device state structure.563 */564 PDMBOTHCBDECL(void) vpciLowerInterrupt(VPCISTATE *pState)565 {566 LogFlow(("%s vpciLowerInterrupt\n", INSTANCE(pState)));567 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 0);568 }569 570 DECLINLINE(uint32_t) vpciGetHostFeatures(PVPCISTATE pState)571 {572 return virtioGetHostFeatures(pState)573 | VPCI_F_NOTIFY_ON_EMPTY;574 }575 576 /**577 * Port I/O Handler for IN operations.578 *579 * @returns VBox status code.580 *581 * @param pDevIns The device instance.582 * @param pvUser Pointer to the device state structure.583 * @param port Port number used for the IN operation.584 * @param pu32 Where to store the result.585 * @param cb Number of bytes read.586 * @thread EMT587 */588 PDMBOTHCBDECL(int) vpciIOPortIn(PPDMDEVINS pDevIns, void *pvUser,589 RTIOPORT port, uint32_t *pu32, unsigned cb)590 {591 VPCISTATE *pState = PDMINS_2_DATA(pDevIns, VPCISTATE *);592 int rc = VINF_SUCCESS;593 const char *szInst = INSTANCE(pState);594 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatIORead), a);595 596 port -= pState->addrIOPort;597 switch (port)598 {599 case VPCI_HOST_FEATURES:600 /* Tell the guest what features we support. */601 *pu32 = vpciGetHostFeatures(pState) | VPCI_F_BAD_FEATURE;602 break;603 604 case VPCI_GUEST_FEATURES:605 *pu32 = pState->uGuestFeatures;606 break;607 608 case VPCI_QUEUE_PFN:609 *pu32 = pState->Queues[pState->uQueueSelector].uPageNumber;610 break;611 612 case VPCI_QUEUE_NUM:613 Assert(cb == 2);614 *(uint16_t*)pu32 = pState->Queues[pState->uQueueSelector].VRing.uSize;615 break;616 617 case VPCI_QUEUE_SEL:618 Assert(cb == 2);619 *(uint16_t*)pu32 = pState->uQueueSelector;620 break;621 622 case VPCI_STATUS:623 Assert(cb == 1);624 *(uint8_t*)pu32 = pState->uStatus;625 break;626 627 case VPCI_ISR:628 Assert(cb == 1);629 *(uint8_t*)pu32 = pState->uISR;630 pState->uISR = 0; /* read clears all interrupts */631 vpciLowerInterrupt(pState);632 break;633 634 default:635 if (port >= VPCI_CONFIG)636 {637 rc = virtioGetConfig(pState, port - VPCI_CONFIG, cb, pu32);638 }639 else640 {641 *pu32 = 0xFFFFFFFF;642 rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "%s virtioIOPortIn: no valid port at offset port=%RTiop cb=%08x\n", szInst, port, cb);643 }644 break;645 }646 Log3(("%s virtioIOPortIn: At %RTiop in %0*x\n", szInst, port, cb*2, *pu32));647 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatIORead), a);648 return rc;649 }650 651 652 /**653 * Port I/O Handler for OUT operations.654 *655 * @returns VBox status code.656 *657 * @param pDevIns The device instance.658 * @param pvUser User argument.659 * @param Port Port number used for the IN operation.660 * @param u32 The value to output.661 * @param cb The value size in bytes.662 * @thread EMT663 */664 PDMBOTHCBDECL(int) vpciIOPortOut(PPDMDEVINS pDevIns, void *pvUser,665 RTIOPORT port, uint32_t u32, unsigned cb)666 {667 VPCISTATE *pState = PDMINS_2_DATA(pDevIns, VPCISTATE *);668 int rc = VINF_SUCCESS;669 const char *szInst = INSTANCE(pState);670 bool fHasBecomeReady;671 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatIOWrite), a);672 673 port -= pState->addrIOPort;674 Log3(("%s virtioIOPortOut: At %RTiop out %0*x\n", szInst, port, cb*2, u32));675 676 switch (port)677 {678 case VPCI_GUEST_FEATURES:679 /* Check if the guest negotiates properly, fall back to basics if it does not. */680 if (VPCI_F_BAD_FEATURE & u32)681 {682 Log(("%s WARNING! Guest failed to negotiate properly (guest=%x)\n",683 INSTANCE(pState), u32));684 pState->uGuestFeatures = virtioGetHostMinimalFeatures(pState);685 }686 /* The guest may potentially desire features we don't support! */687 else if (~vpciGetHostFeatures(pState) & u32)688 {689 Log(("%s Guest asked for features host does not support! (host=%x guest=%x)\n",690 INSTANCE(pState), vpciGetHostFeatures(pState), u32));691 pState->uGuestFeatures = vpciGetHostFeatures(pState);692 }693 else694 pState->uGuestFeatures = u32;695 virtioSetHostFeatures(pState, pState->uGuestFeatures);696 break;697 698 case VPCI_QUEUE_PFN:699 /*700 * The guest is responsible for allocating the pages for queues,701 * here it provides us with the page number of descriptor table.702 * Note that we provide the size of the queue to the guest via703 * VIRTIO_PCI_QUEUE_NUM.704 */705 pState->Queues[pState->uQueueSelector].uPageNumber = u32;706 if (u32)707 vqueueInit(&pState->Queues[pState->uQueueSelector], u32);708 else709 virtioReset(pState);710 break;711 712 case VPCI_QUEUE_SEL:713 Assert(cb == 2);714 u32 &= 0xFFFF;715 if (u32 < pState->nQueues)716 pState->uQueueSelector = u32;717 else718 Log3(("%s virtioIOPortOut: Invalid queue selector %08x\n", szInst, u32));719 break;720 721 case VPCI_QUEUE_NOTIFY:722 #ifdef IN_RING3723 Assert(cb == 2);724 u32 &= 0xFFFF;725 if (u32 < pState->nQueues)726 if (pState->Queues[u32].VRing.addrDescriptors)727 pState->Queues[u32].pfnCallback(pState, &pState->Queues[u32]);728 else729 Log(("%s The queue (#%d) being notified has not been initialized.\n",730 INSTANCE(pState), u32));731 else732 Log(("%s Invalid queue number (%d)\n", INSTANCE(pState), u32));733 #else734 rc = VINF_IOM_HC_IOPORT_WRITE;735 #endif736 break;737 738 case VPCI_STATUS:739 Assert(cb == 1);740 u32 &= 0xFF;741 fHasBecomeReady = !(pState->uStatus & VPCI_STATUS_DRV_OK) && (u32 & VPCI_STATUS_DRV_OK);742 pState->uStatus = u32;743 /* Writing 0 to the status port triggers device reset. */744 if (u32 == 0)745 virtioReset(pState);746 else if (fHasBecomeReady)747 virtioReady(pState);748 break;749 750 default:751 if (port >= VPCI_CONFIG)752 rc = virtioSetConfig(pState, port - VPCI_CONFIG, cb, &u32);753 else754 rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "%s virtioIOPortOut: no valid port at offset port=%RTiop cb=%08x\n", szInst, port, cb);755 break;756 }757 758 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatIOWrite), a);759 return rc;760 }761 762 #ifdef IN_RING3763 // Common764 /**765 * Map PCI I/O region.766 *767 * @return VBox status code.768 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.769 * @param iRegion The region number.770 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an771 * I/O port, else it's a physical address.772 * This address is *NOT* relative to pci_mem_base like earlier!773 * @param cb Region size.774 * @param enmType One of the PCI_ADDRESS_SPACE_* values.775 * @thread EMT776 */777 static DECLCALLBACK(int) vpciMap(PPCIDEVICE pPciDev, int iRegion,778 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)779 {780 int rc;781 VPCISTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, VPCISTATE*);782 783 if (enmType != PCI_ADDRESS_SPACE_IO)784 {785 /* We should never get here */786 AssertMsgFailed(("Invalid PCI address space param in map callback"));787 return VERR_INTERNAL_ERROR;788 }789 790 pState->addrIOPort = (RTIOPORT)GCPhysAddress;791 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->addrIOPort, cb, 0,792 vpciIOPortOut, vpciIOPortIn, NULL, NULL, "VirtioNet");793 #ifdef VNET_GC_SUPPORT794 AssertRCReturn(rc, rc);795 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->addrIOPort, cb, 0,796 "vpciIOPortOut", "vpciIOPortIn", NULL, NULL, "VirtioNet");797 AssertRCReturn(rc, rc);798 rc = PDMDevHlpIOPortRegisterGC(pPciDev->pDevIns, pState->addrIOPort, cb, 0,799 "vpciIOPortOut", "vpciIOPortIn", NULL, NULL, "VirtioNet");800 #endif801 AssertRC(rc);802 return rc;803 }804 805 /**806 * Provides interfaces to the driver.807 *808 * @returns Pointer to interface. NULL if the interface is not supported.809 * @param pInterface Pointer to this interface structure.810 * @param enmInterface The requested interface identification.811 * @thread EMT812 */813 static DECLCALLBACK(void *) vpciQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)814 {815 VPCISTATE *pState = IFACE_TO_STATE(pInterface, IBase);816 Assert(&pState->IBase == pInterface);817 switch (enmInterface)818 {819 case PDMINTERFACE_BASE:820 return &pState->IBase;821 case PDMINTERFACE_LED_PORTS:822 return &pState->ILeds;823 default:824 return NULL;825 }826 }827 828 /**829 * Gets the pointer to the status LED of a unit.830 *831 * @returns VBox status code.832 * @param pInterface Pointer to the interface structure.833 * @param iLUN The unit which status LED we desire.834 * @param ppLed Where to store the LED pointer.835 * @thread EMT836 */837 static DECLCALLBACK(int) vpciQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)838 {839 VPCISTATE *pState = IFACE_TO_STATE(pInterface, ILeds);840 int rc = VERR_PDM_LUN_NOT_FOUND;841 842 if (iLUN == 0)843 {844 *ppLed = &pState->led;845 rc = VINF_SUCCESS;846 }847 return rc;848 }849 850 /**851 * Turns on/off the write status LED.852 *853 * @returns VBox status code.854 * @param pState Pointer to the device state structure.855 * @param fOn New LED state.856 */857 void vpciSetWriteLed(PVPCISTATE pState, bool fOn)858 {859 LogFlow(("%s vpciSetWriteLed: %s\n", INSTANCE(pState), fOn?"on":"off"));860 if (fOn)861 pState->led.Asserted.s.fWriting = pState->led.Actual.s.fWriting = 1;862 else863 pState->led.Actual.s.fWriting = fOn;864 }865 866 /**867 * Turns on/off the read status LED.868 *869 * @returns VBox status code.870 * @param pState Pointer to the device state structure.871 * @param fOn New LED state.872 */873 void vpciSetReadLed(PVPCISTATE pState, bool fOn)874 {875 LogFlow(("%s vpciSetReadLed: %s\n", INSTANCE(pState), fOn?"on":"off"));876 if (fOn)877 pState->led.Asserted.s.fReading = pState->led.Actual.s.fReading = 1;878 else879 pState->led.Actual.s.fReading = fOn;880 }881 882 /**883 * Sets 8-bit register in PCI configuration space.884 * @param refPciDev The PCI device.885 * @param uOffset The register offset.886 * @param u16Value The value to store in the register.887 * @thread EMT888 */889 DECLINLINE(void) vpciCfgSetU8(PCIDEVICE& refPciDev, uint32_t uOffset, uint8_t u8Value)890 {891 Assert(uOffset < sizeof(refPciDev.config));892 refPciDev.config[uOffset] = u8Value;893 }894 895 /**896 * Sets 16-bit register in PCI configuration space.897 * @param refPciDev The PCI device.898 * @param uOffset The register offset.899 * @param u16Value The value to store in the register.900 * @thread EMT901 */902 DECLINLINE(void) vpciCfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t u16Value)903 {904 Assert(uOffset+sizeof(u16Value) <= sizeof(refPciDev.config));905 *(uint16_t*)&refPciDev.config[uOffset] = u16Value;906 }907 908 /**909 * Sets 32-bit register in PCI configuration space.910 * @param refPciDev The PCI device.911 * @param uOffset The register offset.912 * @param u32Value The value to store in the register.913 * @thread EMT914 */915 DECLINLINE(void) vpciCfgSetU32(PCIDEVICE& refPciDev, uint32_t uOffset, uint32_t u32Value)916 {917 Assert(uOffset+sizeof(u32Value) <= sizeof(refPciDev.config));918 *(uint32_t*)&refPciDev.config[uOffset] = u32Value;919 }920 921 922 #ifdef DEBUG923 static void vpciDumpState(PVPCISTATE pState, const char *pcszCaller)924 {925 Log2(("vpciDumpState: (called from %s)\n"926 " uGuestFeatures = 0x%08x\n"927 " uQueueSelector = 0x%04x\n"928 " uStatus = 0x%02x\n"929 " uISR = 0x%02x\n",930 pcszCaller,931 pState->uGuestFeatures,932 pState->uQueueSelector,933 pState->uStatus,934 pState->uISR));935 936 for (unsigned i = 0; i < pState->nQueues; i++)937 Log2((" %s queue:\n"938 " VRing.uSize = %u\n"939 " VRing.addrDescriptors = %p\n"940 " VRing.addrAvail = %p\n"941 " VRing.addrUsed = %p\n"942 " uNextAvailIndex = %u\n"943 " uNextUsedIndex = %u\n"944 " uPageNumber = %x\n",945 pState->Queues[i].pcszName,946 pState->Queues[i].VRing.uSize,947 pState->Queues[i].VRing.addrDescriptors,948 pState->Queues[i].VRing.addrAvail,949 pState->Queues[i].VRing.addrUsed,950 pState->Queues[i].uNextAvailIndex,951 pState->Queues[i].uNextUsedIndex,952 pState->Queues[i].uPageNumber));953 }954 #else955 # define vpciDumpState(x, s) do {} while (0)956 #endif957 958 /**959 * Saves the state of device.960 *961 * @returns VBox status code.962 * @param pDevIns The device instance.963 * @param pSSM The handle to the saved state.964 */965 static DECLCALLBACK(int) vpciSaveExec(PVPCISTATE pState, PSSMHANDLE pSSM)966 {967 int rc;968 969 vpciDumpState(pState, "vpciSaveExec");970 971 rc = SSMR3PutU32(pSSM, pState->uGuestFeatures);972 AssertRCReturn(rc, rc);973 rc = SSMR3PutU16(pSSM, pState->uQueueSelector);974 AssertRCReturn(rc, rc);975 rc = SSMR3PutU8( pSSM, pState->uStatus);976 AssertRCReturn(rc, rc);977 rc = SSMR3PutU8( pSSM, pState->uISR);978 AssertRCReturn(rc, rc);979 980 /* Save queue states */981 rc = SSMR3PutU32(pSSM, pState->nQueues);982 AssertRCReturn(rc, rc);983 for (unsigned i = 0; i < pState->nQueues; i++)984 {985 rc = SSMR3PutU16(pSSM, pState->Queues[i].VRing.uSize);986 AssertRCReturn(rc, rc);987 rc = SSMR3PutU32(pSSM, pState->Queues[i].uPageNumber);988 AssertRCReturn(rc, rc);989 rc = SSMR3PutU16(pSSM, pState->Queues[i].uNextAvailIndex);990 AssertRCReturn(rc, rc);991 rc = SSMR3PutU16(pSSM, pState->Queues[i].uNextUsedIndex);992 AssertRCReturn(rc, rc);993 }994 995 return VINF_SUCCESS;996 }997 998 /**999 * Loads a saved device state.1000 *1001 * @returns VBox status code.1002 * @param pDevIns The device instance.1003 * @param pSSM The handle to the saved state.1004 * @param uVersion The data unit version number.1005 * @param uPass The data pass.1006 */1007 static DECLCALLBACK(int) vpciLoadExec(PVPCISTATE pState, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)1008 {1009 int rc;1010 1011 if (uPass == SSM_PASS_FINAL)1012 {1013 /* Restore state data */1014 rc = SSMR3GetU32(pSSM, &pState->uGuestFeatures);1015 AssertRCReturn(rc, rc);1016 rc = SSMR3GetU16(pSSM, &pState->uQueueSelector);1017 AssertRCReturn(rc, rc);1018 rc = SSMR3GetU8( pSSM, &pState->uStatus);1019 AssertRCReturn(rc, rc);1020 rc = SSMR3GetU8( pSSM, &pState->uISR);1021 AssertRCReturn(rc, rc);1022 1023 /* Restore queues */1024 if (uVersion > VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1)1025 {1026 rc = SSMR3GetU32(pSSM, &pState->nQueues);1027 AssertRCReturn(rc, rc);1028 }1029 else1030 pState->nQueues = DEVICE_N_QUEUES;1031 for (unsigned i = 0; i < pState->nQueues; i++)1032 {1033 rc = SSMR3GetU16(pSSM, &pState->Queues[i].VRing.uSize);1034 AssertRCReturn(rc, rc);1035 rc = SSMR3GetU32(pSSM, &pState->Queues[i].uPageNumber);1036 AssertRCReturn(rc, rc);1037 1038 if (pState->Queues[i].uPageNumber)1039 vqueueInit(&pState->Queues[i], pState->Queues[i].uPageNumber);1040 1041 rc = SSMR3GetU16(pSSM, &pState->Queues[i].uNextAvailIndex);1042 AssertRCReturn(rc, rc);1043 rc = SSMR3GetU16(pSSM, &pState->Queues[i].uNextUsedIndex);1044 AssertRCReturn(rc, rc);1045 }1046 }1047 1048 vpciDumpState(pState, "vpciLoadExec");1049 1050 return VINF_SUCCESS;1051 }1052 1053 /**1054 * Set PCI configuration space registers.1055 *1056 * @param pci Reference to PCI device structure.1057 * @thread EMT1058 */1059 static DECLCALLBACK(void) vpciConfigure(PCIDEVICE& pci, VirtioDeviceType enmType)1060 {1061 /* Configure PCI Device, assume 32-bit mode ******************************/1062 PCIDevSetVendorId(&pci, DEVICE_PCI_VENDOR_ID);1063 PCIDevSetDeviceId(&pci, DEVICE_PCI_DEVICE_ID);1064 vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, DEVICE_PCI_SUBSYSTEM_VENDOR_ID);1065 vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_ID, DEVICE_PCI_SUBSYSTEM_ID);1066 1067 /* ABI version, must be equal 0 as of 2.6.30 kernel. */1068 vpciCfgSetU8( pci, VBOX_PCI_REVISION_ID, 0x00);1069 /* Ethernet adapter */1070 vpciCfgSetU8( pci, VBOX_PCI_CLASS_PROG, 0x00);1071 vpciCfgSetU16(pci, VBOX_PCI_CLASS_DEVICE, DEVICE_PCI_CLASS);1072 /* Interrupt Pin: INTA# */1073 vpciCfgSetU8( pci, VBOX_PCI_INTERRUPT_PIN, 0x01);1074 }1075 1076 // TODO: header1077 DECLCALLBACK(int) vpciConstruct(PPDMDEVINS pDevIns, VPCISTATE *pState,1078 int iInstance, VirtioDeviceType enmDevType,1079 unsigned uConfigSize)1080 {1081 int rc = VINF_SUCCESS;1082 /* Init handles and log related stuff. */1083 RTStrPrintf(pState->szInstance, sizeof(pState->szInstance), DEVICE_NAME_FMT, iInstance);1084 pState->enmDevType = enmDevType;1085 1086 pState->pDevInsR3 = pDevIns;1087 pState->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);1088 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);1089 pState->led.u32Magic = PDMLED_MAGIC;1090 1091 pState->ILeds.pfnQueryStatusLed = vpciQueryStatusLed;1092 1093 /* Initialize critical section. */1094 rc = PDMDevHlpCritSectInit(pDevIns, &pState->cs, pState->szInstance);1095 if (RT_FAILURE(rc))1096 return rc;1097 1098 /* Set PCI config registers */1099 vpciConfigure(pState->pciDevice, VIRTIO_NET_ID);1100 /* Register PCI device */1101 rc = PDMDevHlpPCIRegister(pDevIns, &pState->pciDevice);1102 if (RT_FAILURE(rc))1103 return rc;1104 1105 /* Map our ports to IO space. */1106 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, VPCI_CONFIG + uConfigSize,1107 PCI_ADDRESS_SPACE_IO, vpciMap);1108 if (RT_FAILURE(rc))1109 return rc;1110 1111 /* Status driver */1112 PPDMIBASE pBase;1113 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pState->IBase, &pBase, "Status Port");1114 if (RT_FAILURE(rc))1115 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));1116 pState->pLedsConnector = (PPDMILEDCONNECTORS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);1117 1118 pState->nQueues = DEVICE_N_QUEUES;1119 1120 #if defined(VBOX_WITH_STATISTICS)1121 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in GC", "/Devices/VNet%d/IO/ReadGC", iInstance);1122 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in HC", "/Devices/VNet%d/IO/ReadHC", iInstance);1123 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in GC", "/Devices/VNet%d/IO/WriteGC", iInstance);1124 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC", "/Devices/VNet%d/IO/WriteHC", iInstance);1125 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsRaised, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of raised interrupts", "/Devices/VNet%d/Interrupts/Raised", iInstance);1126 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsSkipped, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of skipped interrupts", "/Devices/VNet%d/Interrupts/Skipped", iInstance);1127 #endif /* VBOX_WITH_STATISTICS */1128 1129 return rc;1130 }1131 1132 /**1133 * Destruct PCI-related part of device.1134 *1135 * We need to free non-VM resources only.1136 *1137 * @returns VBox status.1138 * @param pState The device state structure.1139 */1140 static DECLCALLBACK(int) vpciDestruct(VPCISTATE* pState)1141 {1142 Log(("%s Destroying PCI instance\n", INSTANCE(pState)));1143 1144 if (PDMCritSectIsInitialized(&pState->cs))1145 PDMR3CritSectDelete(&pState->cs);1146 1147 return VINF_SUCCESS;1148 }1149 1150 /**1151 * Device relocation callback.1152 *1153 * When this callback is called the device instance data, and if the1154 * device have a GC component, is being relocated, or/and the selectors1155 * have been changed. The device must use the chance to perform the1156 * necessary pointer relocations and data updates.1157 *1158 * Before the GC code is executed the first time, this function will be1159 * called with a 0 delta so GC pointer calculations can be one in one place.1160 *1161 * @param pDevIns Pointer to the device instance.1162 * @param offDelta The relocation delta relative to the old location.1163 *1164 * @remark A relocation CANNOT fail.1165 */1166 static DECLCALLBACK(void) vpciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)1167 {1168 VPCISTATE* pState = PDMINS_2_DATA(pDevIns, VPCISTATE*);1169 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);1170 // TBD1171 }1172 1173 PVQUEUE vpciAddQueue(VPCISTATE* pState, unsigned uSize,1174 void (*pfnCallback)(void *pvState, PVQUEUE pQueue),1175 const char *pcszName)1176 {1177 PVQUEUE pQueue = NULL;1178 /* Find an empty queue slot */1179 for (unsigned i = 0; i < pState->nQueues; i++)1180 {1181 if (pState->Queues[i].VRing.uSize == 0)1182 {1183 pQueue = &pState->Queues[i];1184 break;1185 }1186 }1187 1188 if (!pQueue)1189 {1190 Log(("%s Too many queues being added, no empty slots available!\n", INSTANCE(pState)));1191 }1192 else1193 {1194 pQueue->VRing.uSize = uSize;1195 pQueue->VRing.addrDescriptors = 0;1196 pQueue->uPageNumber = 0;1197 pQueue->pfnCallback = pfnCallback;1198 pQueue->pcszName = pcszName;1199 }1200 1201 return pQueue;1202 }1203 1204 1205 #endif /* IN_RING3 */1206 1207 66 #endif /* VBOX_DEVICE_STRUCT_TESTCASE */ 1208 67 1209 //------------------------- Tear off here: vnet -------------------------------1210 1211 //- TODO: Move to VirtioNet.h -------------------------------------------------1212 68 1213 69 #define VNET_TX_DELAY 150 /* 150 microseconds */ … … 1384 240 AssertCompileSize(VNETCTLHDR, 2); 1385 241 1386 //- TODO: Leave here ----------------------------------------------------------1387 1388 #undef INSTANCE1389 #define INSTANCE(pState) pState->VPCI.szInstance1390 #undef IFACE_TO_STATE1391 #define IFACE_TO_STATE(pIface, ifaceName) ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName)))1392 #define STATUS pState->config.uStatus1393 1394 242 DECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy) 1395 243 { … … 1547 395 } 1548 396 397 /** 398 * Port I/O Handler for IN operations. 399 * 400 * @returns VBox status code. 401 * 402 * @param pDevIns The device instance. 403 * @param pvUser Pointer to the device state structure. 404 * @param port Port number used for the IN operation. 405 * @param pu32 Where to store the result. 406 * @param cb Number of bytes read. 407 * @thread EMT 408 */ 409 PDMBOTHCBDECL(int) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser, 410 RTIOPORT port, uint32_t *pu32, unsigned cb) 411 { 412 return vpciIOPortIn(pDevIns, pvUser, port, pu32, cb, 413 vnetGetHostFeatures, 414 vnetGetConfig); 415 } 416 417 418 /** 419 * Port I/O Handler for OUT operations. 420 * 421 * @returns VBox status code. 422 * 423 * @param pDevIns The device instance. 424 * @param pvUser User argument. 425 * @param Port Port number used for the IN operation. 426 * @param u32 The value to output. 427 * @param cb The value size in bytes. 428 * @thread EMT 429 */ 430 PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, 431 RTIOPORT port, uint32_t u32, unsigned cb) 432 { 433 return vpciIOPortOut(pDevIns, pvUser, port, u32, cb, 434 vnetGetHostMinimalFeatures, 435 vnetGetHostFeatures, 436 vnetSetHostFeatures, 437 vnetReset, 438 vnetReady, 439 vnetSetConfig); 440 } 441 1549 442 1550 443 #ifdef IN_RING3 … … 1899 792 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n", 1900 793 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR))); 1901 vqueueElemFree(&elem);1902 794 break; /* For now we simply ignore the header, but it must be there anyway! */ 1903 795 } … … 2143 1035 "header! (%u < 1 || %u < %u).\n", INSTANCE(pState), elem.nOut, 2144 1036 elem.aSegsOut[0].cb,sizeof(VNETCTLHDR))); 2145 vqueueElemFree(&elem);2146 1037 break; /* Skip the element and hope the next one is good. */ 2147 1038 } … … 2153 1044 INSTANCE(pState), elem.nIn, elem.aSegsIn[elem.nIn - 1].cb, 2154 1045 sizeof(VNETCTLACK))); 2155 vqueueElemFree(&elem);2156 1046 break; /* Skip the element and hope the next one is good. */ 2157 1047 } … … 2330 1220 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured)); 2331 1221 2332 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass );1222 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass, VNET_N_QUEUES); 2333 1223 AssertRCReturn(rc, rc); 2334 1224 … … 2394 1284 2395 1285 /** 1286 * Map PCI I/O region. 1287 * 1288 * @return VBox status code. 1289 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. 1290 * @param iRegion The region number. 1291 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an 1292 * I/O port, else it's a physical address. 1293 * This address is *NOT* relative to pci_mem_base like earlier! 1294 * @param cb Region size. 1295 * @param enmType One of the PCI_ADDRESS_SPACE_* values. 1296 * @thread EMT 1297 */ 1298 static DECLCALLBACK(int) vnetMap(PPCIDEVICE pPciDev, int iRegion, 1299 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType) 1300 { 1301 int rc; 1302 VNETSTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, VNETSTATE*); 1303 1304 if (enmType != PCI_ADDRESS_SPACE_IO) 1305 { 1306 /* We should never get here */ 1307 AssertMsgFailed(("Invalid PCI address space param in map callback")); 1308 return VERR_INTERNAL_ERROR; 1309 } 1310 1311 pState->VPCI.addrIOPort = (RTIOPORT)GCPhysAddress; 1312 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->VPCI.addrIOPort, 1313 cb, 0, vnetIOPortOut, vnetIOPortIn, 1314 NULL, NULL, "VirtioNet"); 1315 #ifdef VNET_GC_SUPPORT 1316 AssertRCReturn(rc, rc); 1317 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->VPCI.addrIOPort, 1318 cb, 0, "vnetIOPortOut", "vnetIOPortIn", 1319 NULL, NULL, "VirtioNet"); 1320 AssertRCReturn(rc, rc); 1321 rc = PDMDevHlpIOPortRegisterGC(pPciDev->pDevIns, pState->VPCI.addrIOPort, 1322 cb, 0, "vnetIOPortOut", "vnetIOPortIn", 1323 NULL, NULL, "VirtioNet"); 1324 #endif 1325 AssertRC(rc); 1326 return rc; 1327 } 1328 1329 /** 2396 1330 * Construct a device instance for a VM. 2397 1331 * … … 2414 1348 /* Initialize PCI part first. */ 2415 1349 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface; 2416 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance, VIRTIO_NET_ID, sizeof(VNetPCIConfig)); 1350 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance, 1351 VNET_NAME_FMT, VNET_PCI_SUBSYSTEM_ID, 1352 VNET_PCI_CLASS, VNET_N_QUEUES); 2417 1353 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive, "RX "); 2418 1354 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit, "TX "); … … 2458 1394 AssertMsgReturn(pState->pTxBuf, 2459 1395 ("Cannot allocate TX buffer for virtio-net device\n"), VERR_NO_MEMORY); 1396 1397 /* Map our ports to IO space. */ 1398 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 1399 VPCI_CONFIG + sizeof(VNetPCIConfig), 1400 PCI_ADDRESS_SPACE_IO, vnetMap); 1401 if (RT_FAILURE(rc)) 1402 return rc; 1403 2460 1404 2461 1405 /* Register save/restore state handlers. */ -
trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp
r24757 r24834 1336 1336 #ifdef VBOX_WITH_VIRTIO 1337 1337 GEN_CHECK_OFF(VPCISTATE, cs); 1338 GEN_CHECK_OFF(VPCISTATE, enmDevType);1339 1338 GEN_CHECK_OFF(VPCISTATE, szInstance); 1340 1339 GEN_CHECK_OFF(VPCISTATE, IBase);
Note:
See TracChangeset
for help on using the changeset viewer.