Changeset 82863 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Jan 27, 2020 5:11:30 AM (5 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
r82827 r82863 31 31 #define LOG_GROUP LOG_GROUP_DEV_VIRTIO 32 32 #define VIRTIONET_WITH_GSO 33 #define VIRTIONET_WITH_MERGEABLE_RX_BUFS34 33 35 34 #include <VBox/vmm/pdmdev.h> … … 60 59 #include "VBoxDD.h" 61 60 62 63 61 #define VIRTIONET_SAVED_STATE_VERSION UINT32_C(1) 64 62 #define VIRTIONET_MAX_QPAIRS 512 … … 69 67 #define VIRTIONET_PREALLOCATE_RX_SEG_COUNT 32 70 68 71 #define QUEUE_NAME(a_pVirtio, a_idxQueue) ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName) 72 #define VIRTQNAME(qIdx) (pThis->aszVirtqNames[qIdx]) 73 #define CBVIRTQNAME(qIdx) RTStrNLen(VIRTQNAME(qIdx), sizeof(VIRTQNAME(qIdx))) 74 #define FEATURE_ENABLED(feature) (pThis->fNegotiatedFeatures & VIRTIONET_F_##feature) 69 #define INSTANCE(pState) pState->szInstanceName 70 #define QUEUE_NAME(a_pVirtio, a_idxQueue) ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName) 71 #define VIRTQNAME(qIdx) (pThis->aszVirtqNames[qIdx]) 72 #define CBVIRTQNAME(qIdx) RTStrNLen(VIRTQNAME(qIdx), sizeof(VIRTQNAME(qIdx))) 73 #define FEATURE_ENABLED(feature) (pThis->fNegotiatedFeatures & VIRTIONET_F_##feature) 75 74 #define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature)) 76 #define FEATURE_OFFERED(feature) (VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature) 77 #define INSTANCE(pState) pState->szInstanceName; 75 #define FEATURE_OFFERED(feature) (VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature) 78 76 79 77 #define SET_LINK_UP(pState) \ … … 85 83 virtioCoreNotifyConfigChanged(&pThis->Virtio) 86 84 87 #define IS_LINK_UP(pState) (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP)85 #define IS_LINK_UP(pState) (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP) 88 86 #define IS_LINK_DOWN(pState) !IS_LINK_UP(pState) 89 87 90 88 /* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */ 91 #define RXQIDX(qPairIdx) (qPairIdx * 2) 92 #define TXQIDX(qPairIdx) (qPairIdx * 2 + 1) 93 #define CTRLQIDX ((pThis->fNegotiatedFeatures & VIRTIONET_F_MQ) ? VIRTIONET_MAX_QPAIRS * 2 + 2 : 4) 94 95 #define RXVIRTQNAME(qPairIdx) (pThis->aszVirtqNames[RXQIDX(qPairIdx)]) 96 #define TXVIRTQNAME(qPairIdx) (pThis->aszVirtqNames[TXQIDX(qPairIdx)]) 89 #define IS_TX_QUEUE(n) ((n) != CTRLQIDX && ((n) & 1)) 90 #define IS_RX_QUEUE(n) ((n) != CTRLQIDX && !IS_TX_QUEUE(n)) 91 #define IS_CTRL_QUEUE(n) ((n) == CTRLQIDX) 92 #define RXQIDX_QPAIR(qPairIdx) (qPairIdx * 2) 93 #define TXQIDX_QPAIR(qPairIdx) (qPairIdx * 2 + 1) 94 #define CTRLQIDX ((pThis->fNegotiatedFeatures & VIRTIONET_F_MQ) ? ((VIRTIONET_MAX_QPAIRS - 1) * 2 + 2) : (2)) 95 96 #define RXVIRTQNAME(qPairIdx) (pThis->aszVirtqNames[RXQIDX_QPAIR(qPairIdx)]) 97 #define TXVIRTQNAME(qPairIdx) (pThis->aszVirtqNames[TXQIDX_QPAIR(qPairIdx)]) 97 98 #define CTLVIRTQNAME(qPairIdx) (pThis->aszVirtqNames[CTRLQIDX]) 98 99 … … 154 155 | VIRTIONET_F_CTRL_RX \ 155 156 | VIRTIONET_F_CTRL_VLAN \ 156 | VIRTIONET_HOST_FEATURES_GSO 157 | VIRTIONET_HOST_FEATURES_GSO \ 158 | VIRTIONET_F_MRG_RXBUF 157 159 158 160 #define PCI_DEVICE_ID_VIRTIONET_HOST 0x1041 /**< Informs guest driver of type of VirtIO device */ … … 185 187 #pragma pack() 186 188 187 #define VIRTIONET_F_LINK_UP RT_BIT_16(1)/**< config status: Link is up */188 #define VIRTIONET_F_ANNOUNCE RT_BIT_16(2)/**< config status: Announce */189 #define VIRTIONET_F_LINK_UP RT_BIT(1) /**< config status: Link is up */ 190 #define VIRTIONET_F_ANNOUNCE RT_BIT(2) /**< config status: Announce */ 189 191 190 192 /** @name VirtIO 1.0 NET Host Device device specific control types … … 347 349 uint64_t fNegotiatedFeatures; 348 350 349 #ifdef VIRTIONET_TX_DELAY350 /** Transmit Delay Timer. */351 TMTIMERHANDLE hTxTimer;352 uint32_t ui;353 uint32_t uAvgDiff;354 uint32_t uMinDiff;355 uint32_t uMaxDiff;356 uint64_t u64NanoTS;357 #else /* !VNET_TX_DELAY */358 /** The event semaphore TX thread waits on. */359 351 SUPSEMEVENT hTxEvent; 360 #endif /* !VNET_TX_DELAY */361 352 362 353 /** Indicates transmission in progress -- only one thread is allowed. */ … … 381 372 382 373 /** N/A: */ 383 bool volatile f MaybeOutOfSpace;374 bool volatile fLeafWantsRxBuffers; 384 375 385 376 /** Flags whether VirtIO core is in ready state */ … … 399 390 400 391 /** No multicast mode - Supresses multicast receive */ 401 uint8_t fNoMultica t;392 uint8_t fNoMulticast; 402 393 403 394 /** No unicast mode - Suppresses unicast receive */ … … 420 411 421 412 /** Bit array of VLAN filter, one bit per VLAN ID. */ 422 uint8_t aVlanFilter[VIRTIONET_MAX_V ID / sizeof(uint8_t)];413 uint8_t aVlanFilter[VIRTIONET_MAX_VLAN_ID / sizeof(uint8_t)]; 423 414 424 415 /* Receive-blocking-related fields ***************************************/ 425 416 426 417 /** EMT: Gets signalled when more RX descriptors become available. */ 427 SUPSEMEVENT hEventMoreRxDescAvail; 428 429 /** Handle of the I/O port range. */ 430 IOMIOPORTHANDLE hIoPorts; 431 432 /** @name Statistic 433 * @{ */ 434 STAMCOUNTER StatReceiveBytes; 435 STAMCOUNTER StatTransmitBytes; 436 STAMCOUNTER StatReceiveGSO; 437 STAMCOUNTER StatTransmitPackets; 438 STAMCOUNTER StatTransmitGSO; 439 STAMCOUNTER StatTransmitChksum; 440 #ifdef VBOX_WITH_STATISTICS 441 STAMPROFILE StatReceive; 442 STAMPROFILE StatReceiveStore; 443 STAMPROFILEADV StatTransmit; 444 STAMPROFILE StatTransmitSend; 445 STAMPROFILE StatRxOverflow; 446 STAMCOUNTER StatRxOverflowWakeup; 447 STAMCOUNTER StatTransmitByNetwork; 448 STAMCOUNTER StatTransmitByThread; 449 #endif 418 SUPSEMEVENT hEventRxDescAvail; 419 450 420 } VIRTIONET; 451 421 /** Pointer to the shared state of the VirtIO Host NET device. */ … … 493 463 R3PTRTYPE(PPDMINETWORKUP) pDrv; 494 464 495 #ifndef VIRTIONET_TX_DELAY496 465 R3PTRTYPE(PPDMTHREAD) pTxThread; 497 #endif498 466 499 467 /** Link Up(/Restore) Timer. */ … … 547 515 #ifdef IN_RING3 /* spans most of the file, at the moment. */ 548 516 517 /** 518 * @callback_method_impl{FNPDMTHREADWAKEUPDEV} 519 */ 520 static DECLCALLBACK(int) virtioNetR3WakeupWorker(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 521 { 522 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 523 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[(uintptr_t)pThread->pvUser].hEvtProcess); 524 } 525 526 /** 527 * Wakeup the RX thread. 528 */ 529 static void virtioNetR3WakeupRxBufWaiter(PPDMDEVINS pDevIns) 530 { 531 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 532 533 AssertReturnVoid(pThis->hEventRxDescAvail != NIL_SUPSEMEVENT); 534 AssertReturnVoid(ASMAtomicReadBool(&pThis->fLeafWantsRxBuffers)); 535 536 Log(("%s Waking downstream driver's Rx buf waiter thread\n", INSTANCE(pThis))); 537 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEventRxDescAvail); 538 AssertRC(rc); 539 } 549 540 550 541 DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis) … … 552 543 for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++) 553 544 { 554 RTStrPrintf(pThis->aszVirtqNames[RXQIDX (qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "receiveq<%d>", qPairIdx);555 RTStrPrintf(pThis->aszVirtqNames[TXQIDX (qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "transmitq<%d>", qPairIdx);545 RTStrPrintf(pThis->aszVirtqNames[RXQIDX_QPAIR(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "receiveq<%d>", qPairIdx); 546 RTStrPrintf(pThis->aszVirtqNames[TXQIDX_QPAIR(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "transmitq<%d>", qPairIdx); 556 547 } 557 548 RTStrCopy(pThis->aszVirtqNames[CTRLQIDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq"); 558 549 } 559 550 551 /** 552 * Dump a packet to debug log. 553 * 554 * @param pThis The virtio-net shared instance data. 555 * @param pbPacket The packet. 556 * @param cb The size of the packet. 557 * @param pszText A string denoting direction of packet transfer. 558 */ 559 DECLINLINE(void) virtioNetR3PacketDump(PVIRTIONET pThis, const uint8_t *pbPacket, size_t cb, const char *pszText) 560 { 561 # ifdef DEBUG 562 # if 0 563 Log(("%s %s packet #%d (%d bytes):\n", 564 INSTANCE(pThis), pszText, ++pThis->u32PktNo, cb)); 565 Log3(("%.*Rhxd\n", cb, pbPacket)); 566 # else 567 vboxEthPacketDump(INSTANCE(pThis), pszText, pbPacket, (uint32_t)cb); 568 # endif 569 # else 570 RT_NOREF4(pThis, pbPacket, cb, pszText); 571 # endif 572 } 560 573 561 574 DECLINLINE(void) virtioNetPrintFeatures(PVIRTIONET pThis, uint32_t fFeatures, const char *pcszText) … … 641 654 } 642 655 643 /** 644 * @callback_method_impl{VIRTIOCORER3,pfnQueueNotified} 645 */ 646 static DECLCALLBACK(void) virtioNetR3Notified(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint16_t qIdx) 647 { 648 PVIRTIONET pThis = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio); 649 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pVirtioCC, VIRTIONETCC, Virtio); 650 PPDMDEVINS pDevIns = pThisCC->pDevIns; 651 AssertReturnVoid(qIdx < pThis->cVirtQueues); 652 PVIRTIONETWORKER pWorker = &pThis->aWorkers[qIdx]; 653 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[qIdx]; 654 655 #ifdef LOG_ENABLED 656 RTLogFlush(NULL); 657 #endif 658 659 Log6Func(("%s has available data\n", VIRTQNAME(qIdx))); 660 /* Wake queue's worker thread up if sleeping */ 661 if (!ASMAtomicXchgBool(&pWorkerR3->fNotified, true)) 662 { 663 if (ASMAtomicReadBool(&pWorkerR3->fSleeping)) 664 { 665 Log6Func(("waking %s worker.\n", VIRTQNAME(qIdx))); 666 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 667 AssertRC(rc); 668 } 669 } 670 } 656 671 657 672 658 … … 725 711 726 712 727 #if 0728 729 713 static int virtioNetR3CfgAccessed(PVIRTIONET pThis, uint32_t offConfig, void *pv, uint32_t cb, bool fWrite) 730 714 { … … 733 717 if (MATCH_NET_CONFIG(uMacAddress)) 734 718 NET_CONFIG_ACCESSOR_READONLY(uMacAddress); 735 #if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_STATUS719 #if FEATURE_OFFERED(STATUS) 736 720 else 737 721 if (MATCH_NET_CONFIG(uStatus)) 738 722 NET_CONFIG_ACCESSOR_READONLY(uStatus); 739 723 #endif 740 #if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_MQ724 #if FEATURE_OFFERED(MQ) 741 725 else 742 726 if (MATCH_NET_CONFIG(uMaxVirtqPairs)) … … 771 755 return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/); 772 756 } 773 774 #endif775 757 776 758 … … 940 922 */ 941 923 924 virtioNetR3WakeupRxBufWaiter(pDevIns); 925 942 926 virtioNetR3QuiesceDevice(pDevIns, enmType); 927 943 928 } 944 929 … … 991 976 } 992 977 993 /**994 * @callback_method_impl{FNIOMIOPORTNEWIN}995 */996 static DECLCALLBACK(VBOXSTRICTRC) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)997 {998 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);999 RT_NOREF(pvUser);1000 return vpciIOPortIn(pDevIns, &pThis->VPCI, offPort, pu32, cb, &g_IOCallbacks);1001 }1002 1003 1004 /**1005 * @callback_method_impl{FNIOMIOPORTNEWOUT}1006 */1007 static DECLCALLBACK(VBOXSTRICTRC) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)1008 {1009 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1010 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);1011 RT_NOREF(pvUser);1012 return vpciIOPortOut(pDevIns, &pThis->VPCI, &pThisCC->VPCI, offPort, u32, cb, &g_IOCallbacks);1013 }1014 1015 978 1016 979 #ifdef IN_RING3 1017 /** 1018 * @interface_method_impl{PDMIBASE,pfnQueryInterface, 1019 * For VNETSTATECC::VPCI.IBase} 1020 */ 1021 static DECLCALLBACK(void *) virtioNetQueryInterface(struct PDMIBASE *pInterface, const char *pszIID) 1022 { 1023 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, VPCI.IBase); 1024 1025 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThisCC->INetworkDown); 1026 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig); 1027 1028 return vpciR3QueryInterface(&pThisCC->VPCI, pszIID); 1029 } 1030 1031 /** 1032 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail} 1033 */ 1034 static DECLCALLBACK(int) virtioNetR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies) 1035 { 1036 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1037 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkDown); 1038 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1039 1040 LogFlowFunc(("%s: cMillies=%u\n", INSTANCE(pThis), cMillies)); 1041 1042 int rc = virtioNetR3CanReceive(pDevIns, pThis, pThisCC); 1043 if (RT_SUCCESS(rc)) 1044 return VINF_SUCCESS; 1045 1046 if (cMillies == 0) 1047 return VERR_NET_NO_BUFFER_SPACE; 1048 1049 rc = VERR_INTERRUPTED; 1050 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true); 1051 STAM_PROFILE_START(&pThis->StatRxOverflow, a); 1052 1053 VMSTATE enmVMState; 1054 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pDevIns)) == VMSTATE_RUNNING 1055 || enmVMState == VMSTATE_RUNNING_LS)) 1056 { 1057 int rc2 = virtioNetR3CanReceive(pDevIns, pThis, pThisCC); 1058 if (RT_SUCCESS(rc2)) 1059 { 1060 rc = VINF_SUCCESS; 1061 break; 1062 } 1063 LogFunc(("%s: waiting cMillies=%u...\n", INSTANCE(pThis), cMillies)); 1064 rc2 = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventMoreRxDescAvail, cMillies); 1065 if (RT_FAILURE(rc2) && rc2 != VERR_TIMEOUT && rc2 != VERR_INTERRUPTED) 1066 RTThreadSleep(1); 1067 } 1068 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a); 1069 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false); 1070 1071 LogFlowFunc(("%s: -> %d\n", INSTANCE(pThis), rc)); 1072 return rc; 1073 } 980 981 982 DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb) 983 { 984 uint32_t chksum = 0; 985 uint16_t *pu = (uint16_t *)pvBuf; 986 987 while (cb > 1) 988 { 989 chksum += *pu++; 990 cb -= 2; 991 } 992 if (cb) 993 chksum += *(uint8_t*)pu; 994 while (chksum >> 16) 995 chksum = (chksum >> 16) + (chksum & 0xFFFF); 996 return ~chksum; 997 } 998 999 DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset) 1000 { 1001 AssertReturnVoid(uStart < cbSize); 1002 AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize); 1003 *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Checkum16(pBuf + uStart, cbSize - uStart); 1004 } 1005 1006 /** 1007 * Turns on/off the read status LED. 1008 * 1009 * @returns VBox status code. 1010 * @param pThis Pointer to the device state structure. 1011 * @param fOn New LED state. 1012 */ 1013 void virtioNetR3SetReadLed(PVIRTIONETR3 pThisR3, bool fOn) 1014 { 1015 Log6Func(("%s\n", fOn ? "on" : "off")); 1016 if (fOn) 1017 pThisR3->led.Asserted.s.fReading = pThisR3->led.Actual.s.fReading = 1; 1018 else 1019 pThisR3->led.Actual.s.fReading = fOn; 1020 } 1021 1022 /** 1023 * Turns on/off the write status LED. 1024 * 1025 * @returns VBox status code. 1026 * @param pThis Pointer to the device state structure. 1027 * @param fOn New LED state. 1028 */ 1029 void virtioNetR3SetWriteLed(PVIRTIONETR3 pThisR3, bool fOn) 1030 { 1031 Log6Func(("%s\n", fOn ? "on" : "off")); 1032 if (fOn) 1033 pThisR3->led.Asserted.s.fWriting = pThisR3->led.Actual.s.fWriting = 1; 1034 else 1035 pThisR3->led.Actual.s.fWriting = fOn; 1036 } 1037 1074 1038 /** 1075 1039 * Check if the device can receive data now. … … 1083 1047 * @thread RX 1084 1048 */ 1085 static int virtioNetR3CanReceive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 1086 { 1087 int rc = virtioNetCsRxEnter(pThis, VERR_SEM_BUSY); 1088 AssertRCReturn(rc, rc); 1049 static int virtioNetR3IsRxQueuePrimed(PPDMDEVINS pDevIns, PVIRTIONET pThis) 1050 { 1051 int rc; 1089 1052 1090 1053 LogFlowFunc(("%s:\n", INSTANCE(pThis))); … … 1093 1056 rc = VERR_NET_NO_BUFFER_SPACE; 1094 1057 1095 else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, RXQIDX (0)))1058 else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, RXQIDX_QPAIR(0))) 1096 1059 rc = VERR_NET_NO_BUFFER_SPACE; 1097 1060 1098 else if (virtioCoreQueueIsEmpty(pDevIns, pThis->Virtio, RXQIDX(0)))1099 { 1100 virtioCoreQueueSetNotify(&pThis-> pVirtio, RXQIDX(0), true);1061 else if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0))) 1062 { 1063 virtioCoreQueueSetNotify(&pThis->Virtio, RXQIDX_QPAIR(0), true); 1101 1064 rc = VERR_NET_NO_BUFFER_SPACE; 1102 1065 } 1103 1066 else 1104 1067 { 1105 virtioCoreQueueSetNotify(&pThis-> pVirtio, RXQIDX(0), false);1068 virtioCoreQueueSetNotify(&pThis->Virtio, RXQIDX_QPAIR(0), false); 1106 1069 rc = VINF_SUCCESS; 1107 1070 } 1108 1071 1109 1072 LogFlowFunc(("%s: -> %Rrc\n", INSTANCE(pThis), rc)); 1110 virtioNetCsRxLeave(pThis);1111 1073 return rc; 1112 1074 } 1113 /** 1114 * @callback_method_impl{FNTMTIMERDEV, Link Up Timer handler.} 1115 */ 1116 static DECLCALLBACK(void) virtioNetR3LinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 1117 { 1118 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1119 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1120 RT_NOREF(pTimer, pvUser); 1121 1122 int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY); 1123 AssertRCReturnVoid(rc); 1124 1125 SET_LINK_UP(pThis); 1126 1127 virtioNetWakeupReceive(pDevIns); 1128 1129 virtioNetR3CsLeave(pDevIns, pThis); 1130 1131 LogFunc(("%s: Link is up\n", INSTANCE(pThis))); 1132 if (pThisCC->pDrv) 1133 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP); 1134 } 1135 1136 1137 /** 1138 * Takes down the link temporarily if it's current status is up. 1139 * 1140 * This is used during restore and when replumbing the network link. 1141 * 1142 * The temporary link outage is supposed to indicate to the OS that all network 1143 * connections have been lost and that it for instance is appropriate to 1144 * renegotiate any DHCP lease. 1145 * 1146 * @param pDevIns The device instance. 1147 * @param pThis The virtio-net shared instance data. 1148 * @param pThisCC The virtio-net ring-3 instance data. 1149 */ 1150 static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 1151 { 1152 if (IS_LINK_UP(pThis)) 1153 { 1154 SET_LINK_DOWN(pThis); 1155 1156 /* Restore the link back in 5 seconds. */ 1157 int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay); 1158 AssertRC(rc); 1159 1160 LogFunc(("%s: Link is down temporarily\n", INSTANCE(pThis))); 1161 } 1162 } 1163 1164 /** 1165 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState} 1166 */ 1167 static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface) 1168 { 1169 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 1170 1171 return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN; 1172 } 1173 1174 /** 1175 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState} 1176 */ 1177 static DECLCALLBACK(int) virtioNetR3NetworkConfig_SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState) 1178 { 1179 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkConfig); 1075 1076 /** 1077 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail} 1078 */ 1079 static DECLCALLBACK(int) virtioNetR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL timeoutMs) 1080 { 1081 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 1180 1082 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1181 1083 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1182 1084 1183 bool fOldUp = !!(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP); 1184 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP; 1185 1186 Log(("%s virtioNetR3NetworkConfig_SetLinkState: enmState=%d\n", INSTANCE(pThis), enmState)); 1187 if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME) 1188 { 1189 if (fOldUp) 1085 LogFlowFunc(("%s: timeoutMs=%u\n", INSTANCE(pThis), timeoutMs)); 1086 1087 if (!timeoutMs) 1088 return VERR_NET_NO_BUFFER_SPACE; 1089 1090 ASMAtomicXchgBool(&pThis->fLeafWantsRxBuffers, true); 1091 1092 VMSTATE enmVMState; 1093 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pDevIns)) == VMSTATE_RUNNING 1094 || enmVMState == VMSTATE_RUNNING_LS)) 1095 { 1096 1097 if (RT_SUCCESS(virtioNetR3IsRxQueuePrimed(pDevIns, pThis))) 1190 1098 { 1191 /* 1192 * We bother to bring the link down only if it was up previously. The UP link state 1193 * notification will be sent when the link actually goes up in virtioNetR3LinkUpTimer(). 1194 */ 1195 virtioNetR3TempLinkDown(pDevIns, pThis, pThisCC); 1196 if (pThisCC->pDrv) 1197 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState); 1099 LogFunc(("Rx bufs now available, releasing waiter...")); 1100 return VINF_SUCCESS; 1198 1101 } 1199 } 1200 else if (fNewUp != fOldUp) 1201 { 1202 if (fNewUp) 1203 { 1204 Log(("%s Link is up\n", INSTANCE(pThis))); 1205 pThis->fCableConnected = true; 1206 pThis->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP; 1207 virtioCoreNotifyConfigChanged(&pThis->Virtio); 1208 } 1209 else 1210 { 1211 /* The link was brought down explicitly, make sure it won't come up by timer. */ 1212 PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer); 1213 Log(("%s Link is down\n", INSTANCE(pThis))); 1214 pThis->fCableConnected = false; 1215 pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP; 1216 virtioCoreNotifyConfigChanged(&pThis->Virtio); 1217 } 1218 if (pThisCC->pDrv) 1219 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState); 1220 } 1221 return VINF_SUCCESS; 1222 } 1223 1224 /** 1225 * @callback_method_impl{FNVPCIQUEUECALLBACK, The RX queue} 1226 */ 1227 static DECLCALLBACK(void) virtioNetR3QueueReceive(PPDMDEVINS pDevIns, PVQUEUE pQueue) 1228 { 1229 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1230 RT_NOREF(pThis, pQueue); 1231 LogFunc(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pThis))); 1232 virtioNetWakeupReceive(pDevIns); 1233 } 1102 LogFunc(("%s: Starved for guest Rx bufs, waiting %u ms ...\n", INSTANCE(pThis), timeoutMs)); 1103 1104 int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventRxDescAvail, timeoutMs); 1105 if (RT_FAILURE(rc) && rc != VERR_TIMEOUT && rc != VERR_INTERRUPTED) 1106 RTThreadSleep(1); 1107 } 1108 ASMAtomicXchgBool(&pThis->fLeafWantsRxBuffers, false); 1109 1110 LogFlowFunc(("%s: Wait for Rx buffers available was interrupted\n", INSTANCE(pThis))); 1111 return VERR_INTERRUPTED; 1112 } 1113 1234 1114 1235 1115 /** … … 1239 1119 * @param pCtx The context descriptor. 1240 1120 */ 1241 DECLINLINE(PPDMNETWORKGSO) virtioNetR3SetupGsoCtx(PPDMNETWORKGSO pGso, V NETHDR const *pHdr)1121 DECLINLINE(PPDMNETWORKGSO) virtioNetR3SetupGsoCtx(PPDMNETWORKGSO pGso, VIRTIONET_PKT_HDR_T const *pPktHdr) 1242 1122 { 1243 1123 pGso->u8Type = PDMNETWORKGSOTYPE_INVALID; 1244 1124 1245 if (p Hdr->u8GSOType & VNETHDR_GSO_ECN)1125 if (pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN) 1246 1126 { 1247 1127 AssertMsgFailed(("Unsupported flag in virtio header: ECN\n")); 1248 1128 return NULL; 1249 1129 } 1250 switch (p Hdr->u8GSOType & ~VNETHDR_GSO_ECN)1251 { 1252 case V NETHDR_GSO_TCPV4:1130 switch (pPktHdr->uGsoType & ~VIRTIONET_HDR_GSO_ECN) 1131 { 1132 case VIRTIONET_HDR_GSO_TCPV4: 1253 1133 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP; 1254 pGso->cbHdrsSeg = p Hdr->u16HdrLen;1134 pGso->cbHdrsSeg = pPktHdr->uHdrLen; 1255 1135 break; 1256 case V NETHDR_GSO_TCPV6:1136 case VIRTIONET_HDR_GSO_TCPV6: 1257 1137 pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP; 1258 pGso->cbHdrsSeg = p Hdr->u16HdrLen;1138 pGso->cbHdrsSeg = pPktHdr->uHdrLen; 1259 1139 break; 1260 case V NETHDR_GSO_UDP:1140 case VIRTIONET_HDR_GSO_UDP: 1261 1141 pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP; 1262 pGso->cbHdrsSeg = p Hdr->u16CSumStart;1142 pGso->cbHdrsSeg = pPktHdr->uChksumStart; 1263 1143 break; 1264 1144 default: 1265 1145 return NULL; 1266 1146 } 1267 if (p Hdr->u8Flags & VNETHDR_F_NEEDS_CSUM)1268 pGso->offHdr2 = p Hdr->u16CSumStart;1147 if (pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM) 1148 pGso->offHdr2 = pPktHdr->uChksumStart; 1269 1149 else 1270 1150 { … … 1273 1153 } 1274 1154 pGso->offHdr1 = sizeof(RTNETETHERHDR); 1275 pGso->cbHdrsTotal = p Hdr->u16HdrLen;1276 pGso->cbMaxSeg = p Hdr->u16GSOSize;1155 pGso->cbHdrsTotal = pPktHdr->uHdrLen; 1156 pGso->cbMaxSeg = pPktHdr->uGsoSize; 1277 1157 return pGso; 1278 1158 } … … 1280 1160 1281 1161 /** 1282 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}1283 */1284 static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)1285 {1286 return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL);1287 }1288 1289 /**1290 1162 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetMac} 1291 1163 */ 1292 1164 static DECLCALLBACK(int) virtioNetR3NetworkConfig_GetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac) 1293 1165 { 1294 PV NETSTATECC pThisCC = RT_FROM_MEMBER(pInterface, VNETSTATECC, INetworkConfig);1295 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PV NETSTATE);1166 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig); 1167 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 1296 1168 memcpy(pMac, pThis->virtioNetConfig.uMacAddress.au8, sizeof(RTMAC)); 1297 1169 return VINF_SUCCESS; 1298 1170 } 1299 #endif1300 1171 1301 1172 /** … … 1339 1210 1340 1211 /* Compare TPID with VLAN Ether Type */ 1341 if ( uPtr[6] == RT_H2BE_ u(0x8100)1342 && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_ u(uPtr[7]) & 0xFFF))1343 { 1344 Log4 func(("%s: not our VLAN, returning false\n", INSTANCE(pThis))));1212 if ( uPtr[6] == RT_H2BE_U16(0x8100) 1213 && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_U16(uPtr[7]) & 0xFFF)) 1214 { 1215 Log4Func(("%s: not our VLAN, returning false\n", INSTANCE(pThis))); 1345 1216 return false; 1346 1217 } … … 1355 1226 return true; 1356 1227 1357 Log4 func(("%s : %RTmac (conf) != %RTmac (dest)\n",1228 Log4Func(("%s : %RTmac (conf) != %RTmac (dest)\n", 1358 1229 INSTANCE(pThis), pThis->virtioNetConfig.uMacAddress.au8, pvBuf)); 1359 1230 … … 1369 1240 1370 1241 Log2Func(("%s: failed all tests, returning false, packet dump follows:\n", 1371 INSTANCE(pThis))) );1242 INSTANCE(pThis))); 1372 1243 1373 1244 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); … … 1392 1263 * @thread RX 1393 1264 */ 1265 1266 /* static void virtioNetR3Receive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain) 1267 { 1268 RT_NOREF5(pDevIns, pThis, pThisCC, qIdx, pDescChain); 1269 } 1270 */ 1394 1271 static int virtioNetR3HandleRxPacket(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1395 1272 const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso) 1396 1273 { 1274 RT_NOREF(pThisCC); 1275 1397 1276 VIRTIONET_PKT_HDR_T rxPktHdr; 1398 1277 … … 1400 1279 { 1401 1280 Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n", 1402 INSTANCE(pThis), pGso->u Type, pGso->cbHdrsTotal,1281 INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal, 1403 1282 pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 1404 1283 1405 1284 rxPktHdr.uFlags = VIRTIONET_HDR_F_NEEDS_CSUM; 1406 switch (pGso->u Type)1285 switch (pGso->u8Type) 1407 1286 { 1408 1287 case PDMNETWORKGSOTYPE_IPV4_TCP: 1409 1288 rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_TCPV4; 1410 rxPktHdr.uC SumOffset = RT_OFFSETOF(RTNETTCP, th_sum);1289 rxPktHdr.uChksumOffset = RT_OFFSETOF(RTNETTCP, th_sum); 1411 1290 break; 1412 1291 case PDMNETWORKGSOTYPE_IPV6_TCP: 1413 1292 rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_TCPV6; 1414 rxPktHdr.uC SumOffset = RT_OFFSETOF(RTNETTCP, th_sum);1293 rxPktHdr.uChksumOffset = RT_OFFSETOF(RTNETTCP, th_sum); 1415 1294 break; 1416 1295 case PDMNETWORKGSOTYPE_IPV4_UDP: 1417 1296 rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_UDP; 1418 rxPktHdr.uC SumOffset = RT_OFFSETOF(RTNETUDP, uh_sum);1297 rxPktHdr.uChksumOffset = RT_OFFSETOF(RTNETUDP, uh_sum); 1419 1298 break; 1420 1299 default: … … 1422 1301 } 1423 1302 rxPktHdr.uHdrLen = pGso->cbHdrsTotal; 1424 rxPktHdr.uGSOSize = pGso->cbMaxSeg; 1425 rxPktHdr.uCSumStart = pGso->offHdr2; 1426 STAM_REL_COUNTER_INC(&pThis->StatReceiveGSO); 1303 rxPktHdr.uGsoSize = pGso->cbMaxSeg; 1304 rxPktHdr.uChksumOffset = pGso->offHdr2; 1427 1305 } 1428 1306 else … … 1434 1312 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1435 1313 1436 PRTSGBUF pSegsBuf; 1437 PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2); 1438 AssertReturn(paSegs, VERR_NO_MEMORY); 1439 RTSgBufInit(pSegsBuf, paSegs, cSegs); 1440 1441 RTGCPHYS physPktHdrNumBufs, cDescs = 0; 1314 uint16_t cSegsAllocated = VIRTIONET_PREALLOCATE_RX_SEG_COUNT; 1315 1316 PRTSGBUF pVirtSegBufToGuest = NULL; 1317 PRTSGSEG paVirtSegsToGuest = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * cSegsAllocated); 1318 AssertReturn(paVirtSegsToGuest, VERR_NO_MEMORY); 1319 1320 RTGCPHYS gcPhysPktHdrNumBuffers; 1321 uint32_t cDescs = 0; 1442 1322 1443 1323 uint8_t fAddPktHdr = true; 1444 for (uint32_t uOffset = 0; uOffset < cb; ) 1324 uint32_t uOffset; 1325 1326 while (uOffset < cb) 1445 1327 { 1446 1328 PVIRTIO_DESC_CHAIN_T pDescChain; 1447 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX (0), &pDescChain, true);1448 1449 AssertRC(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE , rc);1329 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0), &pDescChain, true); 1330 1331 AssertRC(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE); 1450 1332 1451 1333 /** @todo Find a better way to deal with this */ … … 1455 1337 VERR_INTERNAL_ERROR); 1456 1338 1457 /* It's almost inconceivable that the first segment of the guest Rx s/g buf is smaller 1458 * than 12 bytes (i.e. size of virtio_net_hdr). Smaller hasn't been seen in practice. 1459 * To simplify the code, that constraint is implemented here. If a guest OS ever violates 1460 * this assumption, the algorithm can be adapted handle the more complex corner case. */ 1461 1339 /* Unlikely that len of 1st seg of guest Rx (IN) buf is less than sizeof(virtio_net_hdr) == 12. 1340 * Assert it to reduce complexity. Robust solution would entail finding seg idx and offset of 1341 * virtio_net_header.num_buffers (to update field *after* hdr & pkts copied to gcPhys) */ 1462 1342 AssertMsgReturn(pDescChain->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONET_PKT_HDR_T), 1463 ("Desc chain's phys segs haveinsufficient space for pkt header!\n"),1343 ("Desc chain's first seg has insufficient space for pkt header!\n"), 1464 1344 VERR_INTERNAL_ERROR); 1465 1345 … … 1470 1350 { 1471 1351 /* Lead with packet header */ 1472 paSegs[cSegs].cbSeg = sizeof(VIRTIONET_PKT_HDR_T); 1473 paSegs[cSegs].pvSeg = RTMemAlloc(paSegs[0].cb); 1474 AssertReturn(paSegs[0].pvSeg, VERR_NO_MEMORY); 1475 1476 gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0] 1477 + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers); 1478 1479 cSegs++; 1352 paVirtSegsToGuest[cSegs].cbSeg = sizeof(VIRTIONET_PKT_HDR_T); 1353 paVirtSegsToGuest[cSegs].pvSeg = RTMemAlloc(sizeof(VIRTIONET_PKT_HDR_T)); 1354 AssertReturn(paVirtSegsToGuest[0].pvSeg, VERR_NO_MEMORY); 1355 1356 /* Calculate & cache the field we will need to update later in gcPhys memory */ 1357 gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0].gcPhys 1358 + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers); 1359 1360 if (cSegs++ >= cSegsAllocated) 1361 { 1362 cSegsAllocated <<= 1; 1363 paVirtSegsToGuest = (PRTSGSEG)RTMemRealloc(paVirtSegsToGuest, sizeof(RTSGSEG) * cSegsAllocated); 1364 AssertReturn(paVirtSegsToGuest, VERR_NO_MEMORY); 1365 } 1366 1480 1367 fAddPktHdr = false; 1481 1368 cbDescChainLeft -= sizeof(VIRTIONET_PKT_HDR_T); … … 1483 1370 1484 1371 /* Append remaining Rx pkt or as much current desc chain has room for */ 1485 uint32_t u Size = RT_MIN(cb, cbDescChainLeft);1486 pa Segs[cSegs].cbSeg = uSize;1487 pa Segs[cSegs++].pvSeg = ((uint8_t)pvBuf) + uOffset;1488 uOffset += u Size;1372 uint32_t uboundedSize = RT_MIN(cb, cbDescChainLeft); 1373 paVirtSegsToGuest[cSegs].cbSeg = uboundedSize; 1374 paVirtSegsToGuest[cSegs++].pvSeg = ((uint8_t *)pvBuf) + uOffset; 1375 uOffset += uboundedSize; 1489 1376 cDescs++; 1490 1377 1491 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, RXQIDX(0), pSegsBuf, pDescChain, true); 1378 RTSgBufInit(pVirtSegBufToGuest, paVirtSegsToGuest, cSegs); 1379 1380 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0), 1381 pVirtSegBufToGuest, pDescChain, true); 1492 1382 1493 1383 if (FEATURE_DISABLED(MRG_RXBUF)) … … 1495 1385 } 1496 1386 1497 /* Fix up pkt hdr (already in guest phys. memory) with number of descriptors to send */ 1498 1499 int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, cDescs, sizeof(cDescs)); 1500 AssertMsgRCReturn(rc, "Failure updating descriptor count in pkt hdr in guest physical memory\n"); 1501 1502 virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX(0)); 1387 /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */ 1388 1389 int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, &cDescs, sizeof(cDescs)); 1390 AssertMsgRCReturn(rc, 1391 ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), 1392 rc); 1393 1394 virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0)); 1503 1395 1504 1396 for (int i = 0; i < 2; i++) 1505 RTMemFree(pa Segs[i].pvSeg);1506 1507 RTMemFree(pa Segs);1508 RTMemFree(p SegsBuf);1397 RTMemFree(paVirtSegsToGuest[i].pvSeg); 1398 1399 RTMemFree(paVirtSegsToGuest); 1400 RTMemFree(pVirtSegBufToGuest); 1509 1401 1510 1402 if (uOffset < cb) 1511 1403 { 1512 Log (("%s virtioNetR3HandleRxPacket:Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb));1404 LogFunc(("%s Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb)); 1513 1405 return VERR_TOO_MUCH_DATA; 1514 1406 } … … 1520 1412 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso} 1521 1413 */ 1522 static DECLCALLBACK(int) virtioNetR3 ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf,1414 static DECLCALLBACK(int) virtioNetR3NetworkDown_ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf, 1523 1415 size_t cb, PCPDMNETWORKGSO pGso) 1524 1416 { 1525 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkDown);1417 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 1526 1418 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1527 1419 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); … … 1529 1421 if (pGso) 1530 1422 { 1531 uint32_t uFeatures = pThis-> VPCI.uGuestFeatures;1532 1533 switch (pGso->u Type)1423 uint32_t uFeatures = pThis->fNegotiatedFeatures; 1424 1425 switch (pGso->u8Type) 1534 1426 { 1535 1427 case PDMNETWORKGSOTYPE_IPV4_TCP: … … 1549 1441 if (!uFeatures) 1550 1442 { 1551 Log2Func(( GSO type (0x%x) not supported\n", INSTANCE(pThis), pGso->uType));1443 Log2Func(("GSO type (0x%x) not supported\n", INSTANCE(pThis), pGso->u8Type)); 1552 1444 return VERR_NOT_SUPPORTED; 1553 1445 } … … 1556 1448 Log2Func(("pvBuf=%p cb=%u pGso=%p\n", INSTANCE(pThis), pvBuf, cb, pGso)); 1557 1449 1558 int rc = virtio R3CanReceive(pDevIns, pThis, pThisCC);1450 int rc = virtioNetR3IsRxQueuePrimed(pDevIns, pThis); 1559 1451 if (RT_FAILURE(rc)) 1560 1452 return rc; … … 1564 1456 if (( enmVMState != VMSTATE_RUNNING 1565 1457 && enmVMState != VMSTATE_RUNNING_LS) 1566 || !(pThis->virtioNetConfig.uStatus & VIRTIONET_ S_LINK_UP))1458 || !(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP)) 1567 1459 return VINF_SUCCESS; 1568 1460 1569 STAM_PROFILE_START(&pThis->StatReceive, a); 1570 virtioNetR3SetReadLed(&pThisCC, true); 1461 virtioNetR3SetReadLed(pThisCC, true); 1571 1462 if (virtioNetR3AddressFilter(pThis, pvBuf, cb)) 1572 1463 { 1573 rc = virtioNetCsRxEnter(pThis, VERR_SEM_BUSY); 1574 if (RT_SUCCESS(rc)) 1575 { 1576 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso); 1577 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb); 1578 virtioNetCsRxLeave(pThis); 1579 } 1580 } 1581 virtioNetR3SetReadLed(&pThisCC, false); 1582 STAM_PROFILE_STOP(&pThis->StatReceive, a); 1464 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso); 1465 } 1466 virtioNetR3SetReadLed(pThisCC, false); 1583 1467 return rc; 1584 1468 } 1585 1469 1586 1587 DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb) 1588 { 1589 uint32_t chksum = 0; 1590 uint16_t *pu = (uint16_t *)pvBuf; 1591 1592 while (cb > 1) 1593 { 1594 chksum += *pu++; 1595 cb -= 2; 1596 } 1597 if (cb) 1598 chksum += *(uint8_t*)pu; 1599 while (chksum >> 16) 1600 chksum = (chksum >> 16) + (chksum & 0xFFFF); 1601 return ~chksum; 1602 } 1603 1604 DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset) 1605 { 1606 AssertReturnVoid(uStart < cbSize); 1607 AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize); 1608 *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Chksum16(pBuf + uStart, cbSize - uStart); 1609 } 1470 /** 1471 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive} 1472 */ 1473 static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb) 1474 { 1475 return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL); 1476 } 1477 1478 1610 1479 1611 1480 /* Read physical bytes from the out segment(s) of descriptor chain */ 1612 static void virtioNetR3PullChain(P VIRTIO_DESC_CHAIN_T pDecChain, void *pv, uint16_t cb)1481 static void virtioNetR3PullChain(PPDMDEVINS pDevIns, PVIRTIO_DESC_CHAIN_T pDescChain, void *pv, uint16_t cb) 1613 1482 { 1614 1483 uint8_t *pb = (uint8_t *)pv; 1615 for (size_t cb = RT_MIN(pDescChain->cbPhysSend, sizeof(VIRTIONET_PKT_HDR_T)); cb; ) 1616 { 1617 size_t cbSeg = cb; 1484 uint16_t cbMin = RT_MIN(pDescChain->cbPhysSend, cb); 1485 while (cbMin) 1486 { 1487 size_t cbSeg = cbMin; 1618 1488 RTGCPHYS GCPhys = virtioCoreSgBufGetNextSegment(pDescChain->pSgPhysSend, &cbSeg); 1619 1489 PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pb, cbSeg); 1620 1490 pb += cbSeg; 1621 cb -= cbSeg; 1622 } 1491 cbMin -= cbSeg; 1492 } 1493 LogFunc(("Pulled %d bytes out of %d bytes requested from descriptor chain\n", cbMin, cb)); 1623 1494 } 1624 1495 1625 1496 1626 1497 static uint8_t virtioNetR3CtrlRx(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1627 PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1628 { 1629 #define LOG_VIRTIONET_FLAG(field) LogFunc(("%s = %d\n", #field, pThis->field)); 1498 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1499 { 1500 1501 #define LOG_VIRTIONET_FLAG(fld) LogFunc(("%s = %d\n", #fld, pThis->fld)) 1630 1502 1631 1503 LogFunc(("")); … … 1643 1515 /* fallthrough */ 1644 1516 case VIRTIONET_CTRL_RX_NOBCAST: 1645 AssertMsgReturn( fFeatures & VIRTIONET_F_CTRL_RX_EXTRA,1646 ("CTRL "extra"cmd w/o VIRTIONET_F_CTRL_RX_EXTRA feature negotiated - skipping\n"),1517 AssertMsgReturn(FEATURE_ENABLED(CTRL_RX_EXTRA), 1518 ("CTRL 'extra' cmd w/o VIRTIONET_F_CTRL_RX_EXTRA feature negotiated - skipping\n"), 1647 1519 VIRTIONET_ERROR); 1648 1520 /* fall out */ … … 1650 1522 1651 1523 uint8_t fOn, fPromiscChanged = false; 1652 virtioNetR3PullChain(pDe scChain, &fOn, RT_MIN(pDescChain->cbPhysSend, sizeof(fOn)));1524 virtioNetR3PullChain(pDevIns, pDescChain, &fOn, RT_MIN(pDescChain->cbPhysSend, sizeof(fOn))); 1653 1525 1654 1526 switch(pCtrlPktHdr->uCmd) … … 1657 1529 pThis->fPromiscuous = !!fOn; 1658 1530 fPromiscChanged = true; 1659 LOG_VIRTIONET_FLAG(fPromiscuous) 1531 LOG_VIRTIONET_FLAG(fPromiscuous); 1660 1532 break; 1661 1533 case VIRTIONET_CTRL_RX_ALLMULTI: … … 1684 1556 if (pThisCC->pDrv && fPromiscChanged) 1685 1557 { 1686 uint8_t fPromiscuous = pThis->fPromiscuous | pThis->fAllMulticast 1558 uint8_t fPromiscuous = pThis->fPromiscuous | pThis->fAllMulticast; 1687 1559 LogFunc(("Setting promiscuous state to %d\n", fPromiscuous)); 1688 1560 pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, fPromiscuous); … … 1693 1565 1694 1566 static uint8_t virtioNetR3CtrlMac(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1695 PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1696 { 1567 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1568 { 1569 RT_NOREF(pThisCC); 1570 1697 1571 #define ASSERT_CTRL_ADDR_SET(v) \ 1698 AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd"), VIRTIONET_ERROR) ;1572 AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd"), VIRTIONET_ERROR) 1699 1573 1700 1574 #define ASSERT_CTRL_TABLE_SET(v) \ 1701 AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd"), VIRTIONET_ERROR); 1702 1703 int cbRemaining = pDescChain.cbPhysSend - sizeof(*pCtrlPktHdr); 1704 1705 switch(pCtrlPktHder->uCmd) 1575 AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd"), VIRTIONET_ERROR) 1576 1577 AssertMsgReturn(pDescChain->cbPhysSend >= sizeof(*pCtrlPktHdr), 1578 ("insufficient descriptor space for ctrl pkt hdr"), 1579 VIRTIONET_ERROR); 1580 1581 size_t cbRemaining = pDescChain->cbPhysSend - sizeof(*pCtrlPktHdr); 1582 1583 switch(pCtrlPktHdr->uCmd) 1706 1584 { 1707 1585 case VIRTIONET_CTRL_MAC_ADDR_SET: … … 1709 1587 /* Set default Rx filter MAC */ 1710 1588 ASSERT_CTRL_ADDR_SET(cbRemaining >= sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN)); 1711 virtioNetR3PullChain(pDe scChain, &pThis->rxFilterMacDefault, sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));1589 virtioNetR3PullChain(pDevIns, pDescChain, &pThis->rxFilterMacDefault, sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN)); 1712 1590 break; 1713 1591 } … … 1718 1596 /* Load unicast MAC filter table */ 1719 1597 ASSERT_CTRL_TABLE_SET(cbRemaining >= sizeof(cMacs)); 1720 virtioNetR3PullChain(pDe scChain, &cMacs, sizeof(cMacs));1598 virtioNetR3PullChain(pDevIns, pDescChain, &cMacs, sizeof(cMacs)); 1721 1599 cbRemaining -= sizeof(cMacs); 1722 1600 uint32_t cbMacs = cMacs * sizeof(RTMAC); 1723 1601 ASSERT_CTRL_TABLE_SET(cbRemaining >= cbMacs); 1724 virtioNetR3PullChain(pDe scChain, &pThis->aMacUnicastFilter, cbMacs);1602 virtioNetR3PullChain(pDevIns, pDescChain, &pThis->aMacUnicastFilter, cbMacs); 1725 1603 cbRemaining -= cbMacs; 1726 1604 pThis->cUnicastFilterMacs = cMacs; … … 1728 1606 /* Load multicast MAC filter table */ 1729 1607 ASSERT_CTRL_TABLE_SET(cbRemaining >= sizeof(cMacs)); 1730 virtioNetR3PullChain(pDe scChain, &cMacs, sizeof(cMacs));1608 virtioNetR3PullChain(pDevIns, pDescChain, &cMacs, sizeof(cMacs)); 1731 1609 cbRemaining -= sizeof(cMacs); 1732 1610 cbMacs = cMacs * sizeof(RTMAC); 1733 1611 ASSERT_CTRL_TABLE_SET(cbRemaining >= cbMacs); 1734 virtioNetR3PullChain(pDe scChain, &pThis->aMacMulticastFilter, cbMacs);1612 virtioNetR3PullChain(pDevIns, pDescChain, &pThis->aMacMulticastFilter, cbMacs); 1735 1613 cbRemaining -= cbMacs; 1736 1614 pThis->cMulticastFilterMacs = cMacs; 1737 1615 1738 1616 #ifdef LOG_ENABLED 1739 LogFunc(("%s: unicast MACs:\n", INSTANCE(pThis))) );1740 for(unsigned i = 0; i < nMacs; i++)1617 LogFunc(("%s: unicast MACs:\n", INSTANCE(pThis))); 1618 for(unsigned i = 0; i < cMacs; i++) 1741 1619 LogFunc((" %RTmac\n", &pThis->aMacUnicastFilter[i])); 1742 1620 1743 LogFunc(("%s: multicast MACs:\n", INSTANCE(pThis))) );1744 for(unsigned i = 0; i < nMacs; i++)1621 LogFunc(("%s: multicast MACs:\n", INSTANCE(pThis))); 1622 for(unsigned i = 0; i < cMacs; i++) 1745 1623 LogFunc((" %RTmac\n", &pThis->aMacUnicastFilter[i])); 1746 1624 #endif … … 1752 1630 1753 1631 static uint8_t virtioNetR3CtrlVlan(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1754 PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1755 { 1632 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1633 { 1634 RT_NOREF(pThisCC); 1635 1756 1636 uint16_t uVlanId; 1757 int cbRemaining = pDescChain.cbPhysSend - sizeof(*pCtrlPktHdr);1637 uint16_t cbRemaining = pDescChain->cbPhysSend - sizeof(*pCtrlPktHdr); 1758 1638 AssertMsgReturn(cbRemaining > sizeof(uVlanId), 1759 1639 ("DESC chain too small for VIRTIO_NET_CTRL_VLAN cmd processing"), VIRTIONET_ERROR); 1760 virtioNetR3PullChain(pDe scChain, &uVlanId, sizeof(uVlanId));1640 virtioNetR3PullChain(pDevIns, pDescChain, &uVlanId, sizeof(uVlanId)); 1761 1641 AssertMsgReturn(uVlanId > VIRTIONET_MAX_VLAN_ID, 1762 1642 ("%s VLAN ID out of range (VLAN ID=%u)\n", INSTANCE(pThis), uVlanId), VIRTIONET_ERROR); … … 1779 1659 PVIRTIO_DESC_CHAIN_T pDescChain) 1780 1660 { 1781 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1782 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1783 1661 1662 #define SIZEOF_SEND(descChain, ctrlHdr) RT_MIN(descChain->cbPhysSend, sizeof(ctrlHdr)) 1784 1663 1785 1664 if (pDescChain->cbPhysSend < 2) … … 1797 1676 * Allocate buffer and read in the control command 1798 1677 */ 1799 PVIRTIONET_PKT_HDR_T pCtrlPktHdr = (PVIRTIONET_PKT_HDR_T)RTMemAllocZ(sizeof(VIRTIONET_PKT_HDR_T)); 1800 AssertPtrReturn(pCtrlPktHdr, VERR_NO_MEMORY /*ignored*/); 1801 1802 AssertMsgReturnVoid(pDescChain >= sizeof(*pCtrlPktHdr), ("DESC chain too small for CTRL pkt header")); 1803 virtioNetR3PullChain(pDescChain, pCtrlPktHdr, SIZEOF_SEND(pDescChain, VIRTIONET_PKT_HDR_T)); 1678 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr = (PVIRTIONET_CTRL_HDR_T)RTMemAllocZ(sizeof(VIRTIONET_CTRL_HDR_T)); 1679 1680 AssertPtrReturnVoid(pCtrlPktHdr); 1681 1682 AssertMsgReturnVoid(pDescChain->cbPhysSend >= sizeof(*pCtrlPktHdr), 1683 ("DESC chain too small for CTRL pkt header")); 1684 1685 virtioNetR3PullChain(pDevIns, pDescChain, pCtrlPktHdr, SIZEOF_SEND(pDescChain, VIRTIONET_CTRL_HDR_T)); 1804 1686 1805 1687 uint8_t uAck; … … 1819 1701 } 1820 1702 1703 int cSegs = 2; 1704 1821 1705 /* Return CTRL packet Ack byte (result code) to guest driver */ 1822 PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2);1823 Assert Return(paSegs, VERR_NO_MEMORY);1706 PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * cSegs); 1707 AssertMsgReturnVoid(paSegs, ("Out of memory")); 1824 1708 1825 1709 RTSGSEG aSegs[] = { { &uAck, sizeof(uAck) } }; … … 1827 1711 1828 1712 PRTSGBUF pSegBuf = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF)); 1829 AssertReturn(pSegBuf, VERR_NO_MEMORY); 1713 AssertMsgReturnVoid(pSegBuf, ("Out of memory")); 1714 1830 1715 1831 1716 /* Copy segment data to malloc'd memory to avoid stack out-of-scope errors sanitizer doesn't detect */ … … 1834 1719 void *pv = paSegs[i].pvSeg; 1835 1720 paSegs[i].pvSeg = RTMemAlloc(paSegs[i].cbSeg); 1836 Assert Return(paSegs[i].pvSeg, VERR_NO_MEMORY);1721 AssertMsgReturnVoid(paSegs[i].pvSeg, ("Out of memory")); 1837 1722 memcpy(paSegs[i].pvSeg, pv, paSegs[i].cbSeg); 1838 1723 } … … 1840 1725 RTSgBufInit(pSegBuf, paSegs, cSegs); 1841 1726 1842 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, pSegBuf, pDescChain, true);1843 virtioCoreQueueSync(pDevIns, &pThis->Virtio, qIdx);1727 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, CTRLQIDX, pSegBuf, pDescChain, true); 1728 virtioCoreQueueSync(pDevIns, &pThis->Virtio, CTRLQIDX); 1844 1729 1845 1730 for (int i = 0; i < cSegs; i++) … … 1850 1735 1851 1736 LogFunc(("Processed ctrl message class/cmd/subcmd = %u/%u/%u. Ack=%u.\n", 1852 pCtrlPktHdr .uClass, pCtrlPktHdr.uCmd, pCtrlPktHdr.uCmdSpecific, uAck);1737 pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd, pCtrlPktHdr->uCmdSpecific, uAck)); 1853 1738 1854 1739 } … … 1861 1746 1862 1747 Log4(("virtio-net: header flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x cb=%x\n", 1863 pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, pPktHdr->uGSOSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax)); 1748 pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, 1749 pPktHdr->uGsoSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax)); 1864 1750 1865 1751 if (pPktHdr->uGsoType) … … 1869 1755 /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */ 1870 1756 if ( RT_UNLIKELY(!(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)) 1871 | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN)) )1757 | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN)) 1872 1758 return false; 1873 1759 … … 1885 1771 } 1886 1772 /* Header + MSS must not exceed the packet size. */ 1887 if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uG SOSize > cbMax))1773 if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGsoSize > cbMax)) 1888 1774 return false; 1889 1775 } … … 1892 1778 && sizeof(uint16_t) + pPktHdr->uChksumStart + pPktHdr->uChksumOffset > cbMax) 1893 1779 return false; 1894 Log4 func(("returning true\n"));1780 Log4Func(("returning true\n")); 1895 1781 return true; 1896 1782 } 1897 1783 1898 1784 static int virtioNetR3TransmitFrame(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMSCATTERGATHER pSgBuf, 1899 PPDMNETWORKGSO pGso, PV NETHDR pHdr)1785 PPDMNETWORKGSO pGso, PVIRTIONET_PKT_HDR_T pPktHdr) 1900 1786 { 1901 1787 virtioNetR3PacketDump(pThis, (uint8_t *)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, "--> Outgoing"); … … 1907 1793 * it gets filled out by different versions of kernels. 1908 1794 */ 1909 //if (pGso->cbHdrs < p Hdr->uCSumStart + pHdr->uCSumOffset + 2)1795 //if (pGso->cbHdrs < pPktHdr->uCSumStart + pPktHdr->uCSumOffset + 2) 1910 1796 { 1911 1797 Log4Func(("%s: HdrLen before adjustment %d.\n", … … 1915 1801 case PDMNETWORKGSOTYPE_IPV4_TCP: 1916 1802 case PDMNETWORKGSOTYPE_IPV6_TCP: 1917 pGso->cbHdrsTotal = p Hdr->uChkumStart +1918 ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + p Hdr->uChkumStart))->th_off * 4;1803 pGso->cbHdrsTotal = pPktHdr->uChksumStart + 1804 ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pPktHdr->uChksumStart))->th_off * 4; 1919 1805 pGso->cbHdrsSeg = pGso->cbHdrsTotal; 1920 1806 break; 1921 1807 case PDMNETWORKGSOTYPE_IPV4_UDP: 1922 pGso->cbHdrsTotal = (uint8_t)(p Hdr->uCSumStart + sizeof(RTNETUDP));1923 pGso->cbHdrsSeg = pHdr->u16CSumStart;1808 pGso->cbHdrsTotal = (uint8_t)(pPktHdr->uChksumStart + sizeof(RTNETUDP)); 1809 pGso->cbHdrsSeg = pPktHdr->uChksumStart; 1924 1810 break; 1925 1811 } … … 1927 1813 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal; 1928 1814 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg = pGso->cbHdrsSeg; 1929 Log4 (("%s vnetR3TransmitPendingPackets: adjusted HdrLen to %d.\n",1815 Log4Func(("%s: adjusted HdrLen to %d.\n", 1930 1816 INSTANCE(pThis), pGso->cbHdrsTotal)); 1931 1817 } … … 1933 1819 INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg, 1934 1820 pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 1935 STAM_REL_COUNTER_INC(&pThis->StatTransmitGSO); 1936 } 1937 else if (pHdr->u8Flags & VNETHDR_F_NEEDS_CSUM) 1938 { 1939 STAM_REL_COUNTER_INC(&pThis->StatTransmitCSum); 1821 } 1822 else if (pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM) 1823 { 1940 1824 /* 1941 1825 * This is not GSO frame but checksum offloading is requested. 1942 1826 */ 1943 1827 virtioNetR3CompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, 1944 p Hdr->uChkumStart, pHdr->uCSumOffset);1828 pPktHdr->uChksumStart, pPktHdr->uChksumOffset); 1945 1829 } 1946 1830 … … 1948 1832 } 1949 1833 1950 static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PV NETSTATE pThis, PVNETSTATECC pThisCC,1834 static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1951 1835 uint16_t qIdx, bool fOnWorkerThread) 1952 1836 { 1953 PVIRTIOCORE pVirtio = pThis->pVirtio;1837 PVIRTIOCORE pVirtio = &pThis->Virtio; 1954 1838 1955 1839 /* … … 1961 1845 return; 1962 1846 1963 if (! fVirtioReady)1847 if (!pThis->fVirtioReady) 1964 1848 { 1965 1849 LogFunc(("%s Ignoring transmit requests. VirtIO not ready (status=0x%x).\n", … … 1988 1872 unsigned int cbPktHdr = sizeof(VIRTIONET_PKT_HDR_T); 1989 1873 1990 Log3func(("%s: About to transmit %d pending packets\n", 1991 INSTANCE(pThis), virtioCoreR3QueuePendingCount(pVirtio->pDevIndx, pVirtio, TXQIDX(0)); 1992 1993 virtioNetR3SetWriteLed(&pThisCC, true); 1874 Log3Func(("%s: About to transmit %d pending packets\n", INSTANCE(pThis), 1875 virtioCoreR3QueuePendingCount(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0)))); 1876 1877 virtioNetR3SetWriteLed(pThisCC, true); 1878 1994 1879 1995 1880 PVIRTIO_DESC_CHAIN_T pDescChain; 1996 while (virtioCoreR3QueuePeek(pVirtio->pDevIns, pVirtio, TXQIDX(0), &pDescChain) { 1997 { 1998 unsigned uOffset = 0; 1999 uint32_t cVirtioSegs = pDescChain->pSgPhysSend->cSegs; 2000 PVIRTIOSGSEG paVirtioSegs = pDescChain->pSgPhysSend->paSegs; 2001 2002 if (cVirtioSegs < 2 || paVirtioSegs[0].cbSeg != cbPktHdr) 1881 while (virtioCoreR3QueuePeek(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0), &pDescChain)) 1882 { 1883 uint32_t cSegsFromGuest = pDescChain->pSgPhysSend->cSegs; 1884 PVIRTIOSGSEG paSegsFromGuest = pDescChain->pSgPhysSend->paSegs; 1885 1886 Log6Func(("fetched descriptor chain from %s\n", VIRTQNAME(qIdx))); 1887 1888 if (cSegsFromGuest < 2 || paSegsFromGuest[0].cbSeg != cbPktHdr) 2003 1889 { 2004 1890 /* This check could be made more complex, because in theory (but not likely nor 2005 1891 * seen in practice) the first segment could contain header and data. */ 2006 1892 LogFunc(("%s: The first segment is not the header! (%u < 2 || %u != %u).\n", 2007 INSTANCE(pThis), c VirtioSegs, paVirtioSegs[0].cbSeg, cbPktHdr));1893 INSTANCE(pThis), cSegsFromGuest, paSegsFromGuest[0].cbSeg, cbPktHdr)); 2008 1894 break; 2009 1895 } … … 2013 1899 2014 1900 /* Compute total frame size. */ 2015 for (unsigned i = 1; i < c VirtioSegs&& uSize < VIRTIONET_MAX_FRAME_SIZE; i++)2016 uSize += pa VirtioSegs[i].cbSeg;2017 2018 Log5 func(("%s: complete frame is %u bytes.\n", INSTANCE(pThis), uSize));1901 for (unsigned i = 1; i < cSegsFromGuest && uSize < VIRTIONET_MAX_FRAME_SIZE; i++) 1902 uSize += paSegsFromGuest[i].cbSeg; 1903 1904 Log5Func(("%s: complete frame is %u bytes.\n", INSTANCE(pThis), uSize)); 2019 1905 Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE); 2020 1906 … … 2023 1909 uSize = VIRTIONET_MAX_FRAME_SIZE; 2024 1910 2025 if (pThisCC->pDrv && virtioNetR3ReadHeader(pDevIns, pa VirtioSegs[0].gcPhys, &PktHdr, uSize))1911 if (pThisCC->pDrv && virtioNetR3ReadHeader(pDevIns, paSegsFromGuest[0].gcPhys, &PktHdr, uSize)) 2026 1912 { 2027 1913 PDMNETWORKGSO Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr); 2028 1914 2029 1915 /** @todo Optimize away the extra copying! (lazy bird) */ 2030 PPDMSCATTERGATHER p PdmSgBuf;2031 int rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &p PdmSgBuf);1916 PPDMSCATTERGATHER pSgBufToPdmLeafDevice; 1917 int rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &pSgBufToPdmLeafDevice); 2032 1918 if (RT_SUCCESS(rc)) 2033 1919 { 2034 p PdmSgBuf->cbUsed = uSize;1920 pSgBufToPdmLeafDevice->cbUsed = uSize; 2035 1921 2036 1922 /* Assemble a complete frame. */ 2037 for (unsigned i = 1; i < c VirtioSegs&& uSize > 0; i++)1923 for (unsigned i = 1; i < cSegsFromGuest && uSize > 0; i++) 2038 1924 { 2039 1925 unsigned uOffset; 2040 unsigned cbSeg = RT_MIN(uSize, pa VirtioSegs[i].cbSeg);2041 2042 PDMDevHlpPCIPhysRead(pDevIns, pa VirtioSegs[i].gcPhys;2043 ((uint8_t *)p PdmSgBuf->aSegs[0].pvSeg) + uOffset,1926 unsigned cbSeg = RT_MIN(uSize, paSegsFromGuest[i].cbSeg); 1927 1928 PDMDevHlpPCIPhysRead(pDevIns, paSegsFromGuest[i].gcPhys, 1929 ((uint8_t *)pSgBufToPdmLeafDevice->aSegs[0].pvSeg) + uOffset, 2044 1930 cbSeg); 2045 1931 uOffset += cbSeg; 2046 1932 uSize -= cbSeg; 2047 1933 } 2048 rc = virtioNetR3TransmitFrame(pThis, pThisCC, p PdmSgBuf, pGso, &PktHdr);1934 rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, &PktHdr); 2049 1935 } 2050 1936 else 2051 1937 { 2052 Log4 func(("Failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc));1938 Log4Func(("Failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc)); 2053 1939 /* Stop trying to fetch TX descriptors until we get more bandwidth. */ 2054 1940 break; … … 2057 1943 2058 1944 /* Remove this descriptor chain from the available ring */ 2059 virtioCoreR3QueueSkip(pVirtio, TXQIDX (0));1945 virtioCoreR3QueueSkip(pVirtio, TXQIDX_QPAIR(0)); 2060 1946 2061 1947 /* No data to return to guest, but call is needed put elem (e.g. desc chain) on used ring */ 2062 virtioCoreR3QueuePut(pVirtio->pDevIns, pVirtio, TXQIDX(0), NULL, pDescChain, false); 2063 2064 virtioCoreQueueSync(pVirtio->pDevIns, pVirtio, TXQIDX(0)); 1948 virtioCoreR3QueuePut(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0), NULL, pDescChain, false); 1949 1950 virtioCoreQueueSync(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0)); 1951 2065 1952 } 2066 1953 virtioNetR3SetWriteLed(pThisCC, false); … … 2074 1961 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending} 2075 1962 */ 2076 static DECLCALLBACK(void) v netR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)1963 static DECLCALLBACK(void) virtioNetR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface) 2077 1964 { 2078 1965 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 2079 1966 PPDMDEVINS pDevIns = pThisCC->pDevIns; 2080 1967 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 2081 vnetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); 2082 } 2083 2084 # ifdef VNET_TX_DELAY 2085 2086 /** 2087 * @callback_method_impl{FNVPCIQUEUECALLBACK, The TX queue} 2088 */ 2089 static DECLCALLBACK(void) virtioNetR3QueueTransmit(PPDMDEVINS pDevIns, PVQUEUE pQueue) 2090 { 2091 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2092 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2093 2094 if (PDMDevHlpTimerIsActive(pDevIns, pThis->hTxTimer)) 2095 { 2096 PDMDevHlpTimerStop(pDevIns, pThis->hTxTimer); 2097 Log3Func(("%: Got kicked with notification disabled, re-enable notification and flush TX queue\n", INSTANCE(pThis))); 2098 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); 2099 if (RT_FAILURE(virtioNettR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY))) 2100 LogRelFunc(("Failed to enter critical section!/n")); 2101 else 1968 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX_QPAIR(0), false /*fOnWorkerThread*/); 1969 } 1970 1971 /** 1972 * @callback_method_impl{VIRTIOCORER3,pfnQueueNotified} 1973 */ 1974 static DECLCALLBACK(void) virtioNetR3QueueNotified(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint16_t qIdx) 1975 { 1976 PVIRTIONET pThis = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio); 1977 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pVirtioCC, VIRTIONETCC, Virtio); 1978 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1979 PVIRTIONETWORKER pWorker = &pThis->aWorkers[qIdx]; 1980 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[qIdx]; 1981 AssertReturnVoid(qIdx < pThis->cVirtQueues); 1982 1983 #ifdef LOG_ENABLED 1984 RTLogFlush(NULL); 1985 #endif 1986 1987 Log6Func(("%s has available buffers\n", VIRTQNAME(qIdx))); 1988 1989 if (IS_RX_QUEUE(qIdx)) 1990 { 1991 LogFunc(("%s Receive buffers has been added, waking up receive thread.\n", 1992 INSTANCE(pThis))); 1993 virtioNetR3WakeupRxBufWaiter(pDevIns); 1994 } 1995 else 1996 { 1997 /* Wake queue's worker thread up if sleeping */ 1998 if (!ASMAtomicXchgBool(&pWorkerR3->fNotified, true)) 2102 1999 { 2103 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), true); 2104 virtioNetR3CsLeave(pDevIns, pThis); 2000 if (ASMAtomicReadBool(&pWorkerR3->fSleeping)) 2001 { 2002 Log6Func(("waking %s worker.\n", VIRTQNAME(qIdx))); 2003 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 2004 AssertRC(rc); 2005 } 2105 2006 } 2106 2007 } 2107 else2108 {2109 if (RT_FAILURE(virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY)))2110 LogRelFunc(("Failed to enter critical section!/n"));2111 else2112 {2113 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), false);2114 PDMDevHlpTimerSetMicro(pDevIns, pThis->hTxTimer, VNET_TX_DELAY);2115 pThis->u64NanoTS = RTTimeNanoTS();2116 virtioNetR3CsLeave(pDevIns, pThis);2117 }2118 }2119 }2120 2121 /**2122 * @callback_method_impl{FNTMTIMERDEV, Transmit Delay Timer handler.}2123 */2124 static DECLCALLBACK(void) virtioNetR3TxTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)2125 {2126 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);2127 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);2128 RT_NOREF(pTimer, pvUser);2129 2130 uint32_t u32MicroDiff = (uint32_t)((RTTimeNanoTS() - pThis->u64NanoTS) / 1000);2131 if (u32MicroDiff < pThis->u32MinDiff)2132 pThis->u32MinDiff = u32MicroDiff;2133 if (u32MicroDiff > pThis->u32MaxDiff)2134 pThis->u32MaxDiff = u32MicroDiff;2135 pThis->u32AvgDiff = (pThis->u32AvgDiff * pThis->u32i + u32MicroDiff) / (pThis->u32i + 1);2136 pThis->u32i++;2137 Log3Func(("Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n",2138 u32MicroDiff, pThis->u32AvgDiff, pThis->u32MinDiff, pThis->u32MaxDiff));2139 2140 // Log3Func(("%s Expired\n", INSTANCE(pThis)));2141 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/);2142 if (RT_FAILURE(virtioNettR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY)))2143 {2144 LogRelFunc(("Failed to enter critical section!/n"));2145 return;2146 }2147 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), true);2148 virtioNetR3CsLeave(pDevIns, pThis);2149 }2150 2151 DECLINLINE(int) virtioNetR3CreateTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)2152 {2153 RT_NOREF(pDevIns, pThis, pThisCC);2154 return VINF_SUCCESS;2155 }2156 2157 DECLINLINE(void) virtioNetR3DestroyTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)2158 {2159 RT_NOREF(pDevIns, pThis, pThisCC);2160 }2161 2162 # else /* !VNET_TX_DELAY */2163 2164 /**2165 * @callback_method_impl{FNPDMTHREADDEV}2166 */2167 static DECLCALLBACK(int) vnetR3TxThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)2168 {2169 PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE);2170 PVNETSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVNETSTATECC);2171 2172 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)2173 return VINF_SUCCESS;2174 2175 int rc = VINF_SUCCESS;2176 while (pThread->enmState == PDMTHREADSTATE_RUNNING)2177 {2178 rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hTxEvent, RT_INDEFINITE_WAIT);2179 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))2180 break;2181 while (true)2182 {2183 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); /// @todo shouldn't it be true instead?2184 LogFunc(("Enable kicking and get to sleep\n"));2185 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), true);2186 if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, TXQIDX(0)))2187 break;2188 virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), false);2189 }2190 }2191 2192 return rc;2193 }2194 2195 /**2196 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}2197 */2198 static DECLCALLBACK(int) virtioNetR3TxThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)2199 {2200 PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE);2201 RT_NOREF(pThread);2202 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTxEvent);2203 }2204 2205 static int vnetR3CreateTxThreadAndEvent(PPDMDEVINS pDevIns, PVNETSTATE pThis, PVNETSTATECC pThisCC)2206 {2207 int rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hTxEvent);2208 if (RT_SUCCESS(rc))2209 {2210 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pTxThread, NULL, vnetR3TxThread,2211 vnetR3TxThreadWakeUp, 0, RTTHREADTYPE_IO, INSTANCE(pThis));2212 if (RT_FAILURE(rc))2213 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("VNET: Failed to create worker thread %s"), INSTANCE(pThis));2214 }2215 else2216 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("VNET: Failed to create SUP event semaphore"));2217 return rc;2218 }2219 2220 static void vnetR3DestroyTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)2221 {2222 if (pThisCC->pTxThread)2223 {2224 /* Destroy the thread. */2225 int rcThread;2226 int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->pTxThread, &rcThread);2227 if (RT_FAILURE(rc) || RT_FAILURE(rcThread))2228 AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));2229 pThisCC->pTxThread = NULL;2230 }2231 2232 if (pThis->hTxEvent != NIL_SUPSEMEVENT)2233 {2234 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hTxEvent);2235 pThis->hTxEvent = NIL_SUPSEMEVENT;2236 }2237 }2238 2239 /**2240 * @callback_method_impl{FNVPCIQUEUECALLBACK, The TX queue}2241 */2242 static DECLCALLBACK(void) virtioNetR3QueueTransmit(PPDMDEVINS pDevIns, uint16_t qIdx)2243 {2244 PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE);2245 2246 LogFunc(("Disable kicking and wake up TX thread\n"));2247 virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false);2248 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTxEvent);2249 AssertRC(rc);2250 }2251 2252 # endif /* !VNET_TX_DELAY */2253 static void virtioNetR3Transmit(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)2254 {2255 RT_NOREF5(pDevIns, pThis, pThisCC, qIdx, pDescChain);2256 }2257 static void virtioNetR3Receive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)2258 {2259 RT_NOREF5(pDevIns, pThis, pThisCC, qIdx, pDescChain);2260 }2261 2262 /**2263 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}2264 */2265 static DECLCALLBACK(int) virtioNetR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)2266 {2267 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);2268 return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[(uintptr_t)pThread->pvUser].hEvtProcess);2269 2008 } 2270 2009 … … 2285 2024 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 2286 2025 { 2026 2027 virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, true); 2028 2287 2029 if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, qIdx)) 2288 2030 { … … 2299 2041 return VINF_SUCCESS; 2300 2042 if (rc == VERR_INTERRUPTED) 2043 { 2044 virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false); 2301 2045 continue; 2046 } 2302 2047 Log6Func(("%s worker woken\n", VIRTQNAME(qIdx))); 2303 2048 ASMAtomicWriteBool(&pWorkerR3->fNotified, false); … … 2306 2051 } 2307 2052 2053 virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false); 2054 2308 2055 if (!pThis->afQueueAttached[qIdx]) 2309 2056 { … … 2311 2058 break; 2312 2059 } 2060 2061 /* Dispatch to the handler for the queue this worker is set up to drive */ 2062 2313 2063 if (!pThisCC->fQuiescing) 2314 2064 { 2315 Log6Func(("fetching next descriptor chain from %s\n", VIRTQNAME(qIdx))); 2316 PVIRTIO_DESC_CHAIN_T pDescChain; 2317 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, qIdx, &pDescChain, true); 2318 if (rc == VERR_NOT_AVAILABLE) 2065 if (IS_CTRL_QUEUE(qIdx)) 2319 2066 { 2320 Log6Func(("Nothing found in %s\n", VIRTQNAME(qIdx))); 2321 continue; 2067 Log6Func(("fetching next descriptor chain from %s\n", VIRTQNAME(qIdx))); 2068 PVIRTIO_DESC_CHAIN_T pDescChain; 2069 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, qIdx, &pDescChain, true); 2070 if (rc == VERR_NOT_AVAILABLE) 2071 { 2072 Log6Func(("Nothing found in %s\n", VIRTQNAME(qIdx))); 2073 continue; 2074 } 2075 virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pDescChain); 2322 2076 } 2323 2324 AssertRC(rc); 2325 if (qIdx == CTRLQIDX) 2326 virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pDescChain); 2327 else if (qIdx & 1) 2328 virtioNetR3Transmit(pDevIns, pThis, pThisCC, qIdx, pDescChain); 2329 else 2330 virtioNetR3Receive(pDevIns, pThis, pThisCC, qIdx, pDescChain); 2077 else if (IS_TX_QUEUE(qIdx)) 2078 { 2079 Log6Func(("Notified of data to transmit\n")); 2080 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, 2081 qIdx, true /* fOnWorkerThread */); 2082 } 2083 /* Rx queues aren't handled by our worker threads. Instead, the PDM network 2084 * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback, 2085 * which waits until notified directly by virtioNetR3QueueNotified() 2086 * that guest IN buffers have been added to receive virt queue. */ 2331 2087 } 2332 2088 } … … 2334 2090 } 2335 2091 2336 #ifdef IN_RING32337 2338 /** Returns true if large packets are written into several RX buffers. */2339 DECLINLINE(bool) virtioNetR3MergeableRxBuffers(PVIRTIONET pThis)2340 {2341 return !!(pThis->fFeatures & VIRTIONET_F_MRG_RXBUF);2342 }2343 2344 2092 DECLINLINE(int) virtioNetR3CsEnter(PPDMDEVINS pDevIns, PVIRTIONET pThis, int rcBusy) 2345 2093 { 2094 RT_NOREF(pDevIns, pThis, rcBusy); 2346 2095 /* Original DevVirtioNet uses CS in attach/detach/link-up timer/tx timer/transmit */ 2347 LogFunc("CS unimplemented. What does the critical section protect in orig driver??")); 2096 LogFunc(("CS unimplemented. What does the critical section protect in orig driver??")); 2097 return VINF_SUCCESS; 2348 2098 } 2349 2099 2350 2100 DECLINLINE(void) virtioNetR3CsLeave(PPDMDEVINS pDevIns, PVIRTIONET pThis) 2351 2101 { 2352 LogFunc("CS unimplemented. What does the critical section protect in orig driver??")); 2353 } 2102 RT_NOREF(pDevIns, pThis); 2103 LogFunc(("CS unimplemented. What does the critical section protect in orig driver??")); 2104 } 2105 2106 2107 /** 2108 * @callback_method_impl{FNTMTIMERDEV, Link Up Timer handler.} 2109 */ 2110 static DECLCALLBACK(void) virtioNetR3LinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 2111 { 2112 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2113 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2114 RT_NOREF(pTimer, pvUser); 2115 2116 int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY); 2117 AssertRCReturnVoid(rc); 2118 2119 SET_LINK_UP(pThis); 2120 2121 virtioNetR3WakeupRxBufWaiter(pDevIns); 2122 2123 virtioNetR3CsLeave(pDevIns, pThis); 2124 2125 LogFunc(("%s: Link is up\n", INSTANCE(pThis))); 2126 if (pThisCC->pDrv) 2127 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP); 2128 } 2129 2130 /** 2131 * Takes down the link temporarily if it's current status is up. 2132 * 2133 * This is used during restore and when replumbing the network link. 2134 * 2135 * The temporary link outage is supposed to indicate to the OS that all network 2136 * connections have been lost and that it for instance is appropriate to 2137 * renegotiate any DHCP lease. 2138 * 2139 * @param pDevIns The device instance. 2140 * @param pThis The virtio-net shared instance data. 2141 * @param pThisCC The virtio-net ring-3 instance data. 2142 */ 2143 static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2144 { 2145 if (IS_LINK_UP(pThis)) 2146 { 2147 SET_LINK_DOWN(pThis); 2148 2149 /* Restore the link back in 5 seconds. */ 2150 int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay); 2151 AssertRC(rc); 2152 2153 LogFunc(("%s: Link is down temporarily\n", INSTANCE(pThis))); 2154 } 2155 } 2156 2157 /** 2158 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState} 2159 */ 2160 static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface) 2161 { 2162 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig); 2163 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 2164 2165 return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN; 2166 } 2167 2168 /** 2169 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState} 2170 */ 2171 static DECLCALLBACK(int) virtioNetR3NetworkConfig_SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState) 2172 { 2173 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig); 2174 PPDMDEVINS pDevIns = pThisCC->pDevIns; 2175 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2176 2177 bool fOldUp = !!(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP); 2178 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP; 2179 2180 Log(("%s virtioNetR3NetworkConfig_SetLinkState: enmState=%d\n", INSTANCE(pThis), enmState)); 2181 if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME) 2182 { 2183 if (fOldUp) 2184 { 2185 /* 2186 * We bother to bring the link down only if it was up previously. The UP link state 2187 * notification will be sent when the link actually goes up in virtioNetR3LinkUpTimer(). 2188 */ 2189 virtioNetR3TempLinkDown(pDevIns, pThis, pThisCC); 2190 if (pThisCC->pDrv) 2191 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState); 2192 } 2193 } 2194 else if (fNewUp != fOldUp) 2195 { 2196 if (fNewUp) 2197 { 2198 Log(("%s Link is up\n", INSTANCE(pThis))); 2199 pThis->fCableConnected = true; 2200 pThis->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP; 2201 virtioCoreNotifyConfigChanged(&pThis->Virtio); 2202 } 2203 else 2204 { 2205 /* The link was brought down explicitly, make sure it won't come up by timer. */ 2206 PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer); 2207 Log(("%s Link is down\n", INSTANCE(pThis))); 2208 pThis->fCableConnected = false; 2209 pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP; 2210 virtioCoreNotifyConfigChanged(&pThis->Virtio); 2211 } 2212 if (pThisCC->pDrv) 2213 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState); 2214 } 2215 return VINF_SUCCESS; 2216 } 2217 2354 2218 2355 2219 /** … … 2368 2232 { 2369 2233 LogFunc(("VirtIO ready\n-----------------------------------------------------------------------------------------\n")); 2370 uint64_t fFeatures = virtioCoreGetNegotiatedFeatures(&pThis->Virtio);2234 // uint64_t fFeatures = virtioCoreGetNegotiatedFeatures(pThis->Virtio); 2371 2235 pThis->fResetting = false; 2372 2236 pThisCC->fQuiescing = false; … … 2379 2243 LogFunc(("VirtIO is resetting\n")); 2380 2244 2381 pThis->virtioNetConfig. status = pThis->fCableConnected ? VIRTIONET_S_LINK_UP : 0;2245 pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0; 2382 2246 LogFunc(("%s Link is %s\n", INSTANCE(pThis), pThis->fCableConnected ? "up" : "down")); 2383 2247 … … 2385 2249 pThis->fAllMulticast = false; 2386 2250 pThis->fAllUnicast = false; 2387 pThis->fNoMultica t= false;2251 pThis->fNoMulticast = false; 2388 2252 pThis->fNoUnicast = false; 2389 2253 pThis->fNoBroadcast = false; … … 2412 2276 static DECLCALLBACK(void) virtioNetR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags) 2413 2277 { 2414 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2415 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2278 RT_NOREF(fFlags); 2279 2280 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2281 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2416 2282 2417 2283 LogFunc(("")); … … 2419 2285 2420 2286 int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY); 2421 AssertMsgRCReturn (rc, ("Failed to enter critical section"), rc);2287 AssertMsgRCReturnVoid(rc, ("Failed to enter critical section")); 2422 2288 2423 2289 /* … … 2478 2344 } 2479 2345 2480 /** 2481 * Turns on/off the write status LED. 2482 * 2483 * @returns VBox status code. 2484 * @param pThis Pointer to the device state structure. 2485 * @param fOn New LED state. 2486 */ 2487 void virtioNetR3SetWriteLed(PVIRTIONETR3 pThisR3, bool fOn) 2488 { 2489 Log6Func(("%s\n", fOn ? "on" : "off")); 2490 if (fOn) 2491 pThisR3->led.Asserted.s.fWriting = pThisR3->led.Actual.s.fWriting = 1; 2492 else 2493 pThisR3->led.Actual.s.fWriting = fOn; 2494 } 2495 2496 /** 2497 * Turns on/off the read status LED. 2498 * 2499 * @returns VBox status code. 2500 * @param pThis Pointer to the device state structure. 2501 * @param fOn New LED state. 2502 */ 2503 void virtioNetR3SetReadLed(PVIRTIONETR3 pThisR3, bool fOn) 2504 { 2505 Log6Func(("%s\n", fOn ? "on" : "off")); 2506 if (fOn) 2507 pThisR3->led.Asserted.s.fReading = pThisR3->led.Actual.s.fReading = 1; 2508 else 2509 pThisR3->led.Actual.s.fReading = fOn; 2510 } 2346 2511 2347 /** 2512 2348 * @interface_method_impl{PDMIBASE,pfnQueryInterface, … … 2514 2350 static DECLCALLBACK(void *) virtioNetR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID) 2515 2351 { 2516 PVIRTIONETR3 pThis R3 = RT_FROM_MEMBER(pInterface, VIRTIONETR3, IBase);2517 2518 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis R3->INetworkDown);2519 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis R3->INetworkConfig);2520 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis R3->IBase);2521 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis R3->ILeds);2352 PVIRTIONETR3 pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, IBase); 2353 2354 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThisCC->INetworkDown); 2355 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig); 2356 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase); 2357 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->ILeds); 2522 2358 return NULL; 2523 2359 } … … 2529 2365 { 2530 2366 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 2367 2531 2368 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2532 2369 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2533 2534 2370 2535 2371 for (unsigned qIdx = 0; qIdx < pThis->cVirtQueues; qIdx++) … … 2541 2377 pWorker->hEvtProcess = NIL_SUPSEMEVENT; 2542 2378 } 2379 if (pThisCC->aWorkers[qIdx].pThread) 2380 { 2381 /* Destroy the thread. */ 2382 int rcThread; 2383 int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[qIdx].pThread, &rcThread); 2384 if (RT_FAILURE(rc) || RT_FAILURE(rcThread)) 2385 AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread)); 2386 pThisCC->aWorkers[qIdx].pThread = NULL; 2387 } 2543 2388 } 2544 2389 … … 2566 2411 pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface; 2567 2412 pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed; 2568 pThisCC->led.uMagic = PDMLED_MAGIC; 2413 pThisCC->led.u32Magic = PDMLED_MAGIC; 2414 2415 /* Interfaces */ 2416 pThisCC->INetworkDown.pfnWaitReceiveAvail = virtioNetR3NetworkDown_WaitReceiveAvail; 2417 pThisCC->INetworkDown.pfnReceive = virtioNetR3NetworkDown_Receive; 2418 pThisCC->INetworkDown.pfnReceiveGso = virtioNetR3NetworkDown_ReceiveGso; 2419 pThisCC->INetworkDown.pfnXmitPending = virtioNetR3NetworkDown_XmitPending; 2420 pThisCC->INetworkConfig.pfnGetMac = virtioNetR3NetworkConfig_GetMac; 2421 pThisCC->INetworkConfig.pfnGetLinkState = virtioNetR3NetworkConfig_GetLinkState; 2422 pThisCC->INetworkConfig.pfnSetLinkState = virtioNetR3NetworkConfig_SetLinkState; 2569 2423 2570 2424 /* … … 2574 2428 2575 2429 /* Get config params */ 2576 int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", pThis->macConfigured.au , sizeof(pThis->macConfigured));2430 int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", pThis->macConfigured.au8, sizeof(pThis->macConfigured)); 2577 2431 if (RT_FAILURE(rc)) 2578 2432 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get MAC address")); … … 2583 2437 2584 2438 uint32_t uStatNo = iInstance; 2585 rc = pHlp->pfnCFGMQuery uDef(pCfg, "StatNo", &uStatNo, iInstance);2439 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "StatNo", &uStatNo, iInstance); 2586 2440 if (RT_FAILURE(rc)) 2587 2441 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"StatNo\" value")); 2588 2442 2589 rc = pHlp->pfnCFGMQuery uDef(pCfg, "LinkUpDelay", &pThis->cMsLinkUpDelay, 5000); /* ms */2443 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "LinkUpDelay", &pThis->cMsLinkUpDelay, 5000); /* ms */ 2590 2444 if (RT_FAILURE(rc)) 2591 2445 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the value of 'LinkUpDelay'")); … … 2600 2454 2601 2455 /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */ 2602 memcpy(pThis->virtioNetConfig.uMacAddress , pThis->macConfigured.au, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */2456 memcpy(pThis->virtioNetConfig.uMacAddress.au8, pThis->macConfigured.au8, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */ 2603 2457 2604 2458 /* … … 2616 2470 /* Initialize the generic Virtio core: */ 2617 2471 pThisCC->Virtio.pfnStatusChanged = virtioNetR3StatusChanged; 2618 pThisCC->Virtio.pfnQueueNotified = virtioNetR3Notified; 2472 pThisCC->Virtio.pfnQueueNotified = virtioNetR3QueueNotified; 2473 pThisCC->Virtio.pfnDevCapRead = virtioNetR3DevCapRead; 2474 pThisCC->Virtio.pfnDevCapWrite = virtioNetR3DevCapWrite; 2619 2475 2620 2476 VIRTIOPCIPARAMS VirtioPciParams; … … 2639 2495 pThis->cVirtqPairs = pThis->fNegotiatedFeatures & VIRTIONET_F_MQ 2640 2496 ? pThis->virtioNetConfig.uMaxVirtqPairs : 1; 2641 pThis->cVirtQueues = pThis->cVirtqPairs + 1; 2497 pThis->cVirtQueues += pThis->cVirtqPairs * 2; 2498 2499 /* Create Link Up Timer */ 2500 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, virtioNetR3LinkUpTimer, NULL, TMTIMER_FLAGS_NO_CRIT_SECT, 2501 "VirtioNet Link Up Timer", &pThisCC->hLinkUpTimer); 2642 2502 2643 2503 /* … … 2647 2507 2648 2508 /* Attach the queues and create worker threads for them: */ 2649 for (uint16_t qIdx = 0; qIdx < pThis->cVirtQueues; qIdx++) 2650 { 2509 for (uint16_t qIdx = 0; qIdx < pThis->cVirtQueues + 1; qIdx++) 2510 { 2511 2651 2512 rc = virtioCoreR3QueueAttach(&pThis->Virtio, qIdx, VIRTQNAME(qIdx)); 2652 2513 if (RT_FAILURE(rc)) 2514 { 2515 pThis->afQueueAttached[qIdx] = true; 2653 2516 continue; 2517 } 2518 2519 /* Skip creating threads for receive queues, only create for transmit queues & control queue */ 2520 if (IS_RX_QUEUE(qIdx)) 2521 continue; 2522 2654 2523 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->aWorkers[qIdx].pThread, 2655 2524 (void *)(uintptr_t)qIdx, virtioNetR3WorkerThread, 2656 virtioNetR3W orkerWakeUp, 0, RTTHREADTYPE_IO, VIRTQNAME(qIdx));2525 virtioNetR3WakeupWorker, 0, RTTHREADTYPE_IO, VIRTQNAME(qIdx)); 2657 2526 if (rc != VINF_SUCCESS) 2658 2527 { … … 2708 2577 2709 2578 #endif /* !IN_RING3 */ 2579 2710 2580 2711 2581 -
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r82681 r82863 1030 1030 { 1031 1031 PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg]; 1032 uint64_t dstSgStart = (uint64_t)paSeg-> pGcSeg;1032 uint64_t dstSgStart = (uint64_t)paSeg->gcPhys; 1033 1033 uint64_t dstSgLen = (uint64_t)paSeg->cbSeg; 1034 uint64_t dstSgCur = (uint64_t)pSgPhysReturn-> pGcSegCur;1034 uint64_t dstSgCur = (uint64_t)pSgPhysReturn->gcPhysCur; 1035 1035 cbCopied = RT_MIN((uint64_t)pSgBuf->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart)); 1036 PDMDevHlpP hysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->pGcSegCur, pSgBuf->pvSegCur, cbCopied);1036 PDMDevHlpPCIPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->gcPhysCur, pSgBuf->pvSegCur, cbCopied); 1037 1037 RTSgBufAdvance(pSgBuf, cbCopied); 1038 1038 virtioCoreSgBufAdvance(pSgPhysReturn, cbCopied); … … 1071 1071 { 1072 1072 PVIRTIOSGSEG paSeg = &pSgPhysSend->paSegs[pSgPhysSend->idxSeg]; 1073 uint64_t srcSgStart = (uint64_t)paSeg-> pGcSeg;1073 uint64_t srcSgStart = (uint64_t)paSeg->gcPhys; 1074 1074 uint64_t srcSgLen = (uint64_t)paSeg->cbSeg; 1075 uint64_t srcSgCur = (uint64_t)pSgPhysSend-> pGcSegCur;1075 uint64_t srcSgCur = (uint64_t)pSgPhysSend->gcPhysCur; 1076 1076 cbCopied = RT_MIN((uint64_t)pSgBuf->cbSegLeft, srcSgLen - (srcSgCur - srcSgStart)); 1077 1077 PDMDevHlpPCIPhysRead(pDevIns, 1078 (RTGCPHYS)pSgPhysSend-> pGcSegCur, pSgBuf->pvSegCur, cbCopied);1078 (RTGCPHYS)pSgPhysSend->gcPhysCur, pSgBuf->pvSegCur, cbCopied); 1079 1079 RTSgBufAdvance(pSgBuf, cbCopied); 1080 1080 virtioCoreSgBufAdvance(pSgPhysSend, cbCopied); … … 2413 2413 PDMDevHlpSUPSemEventClose(pDevIns, pWorker->hEvtProcess); 2414 2414 pWorker->hEvtProcess = NIL_SUPSEMEVENT; 2415 } 2416 2417 if (pThisCC->aWorkers[qIdx].pThread) 2418 { 2419 /* Destroy the thread. */ 2420 int rcThread; 2421 int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[qIdx].pThread, &rcThread); 2422 if (RT_FAILURE(rc) || RT_FAILURE(rcThread)) 2423 AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n", 2424 __FUNCTION__, rc, rcThread)); 2425 pThisCC->aWorkers[qIdx].pThread = NULL; 2415 2426 } 2416 2427 } -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r82681 r82863 256 256 } 257 257 258 #if 0 /* unused - This may eventually be used to set no-notify for the ring as an optimization */259 258 DECLINLINE(void) virtioWriteUsedFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint32_t fFlags) 260 259 { … … 265 264 &fFlags, sizeof(fFlags)); 266 265 } 267 #endif268 266 269 267 #if 0 /* unused - *May* be used when VIRTIO_F_EVENT_IDX optional feature is implemented VirtIO 1.0, 2.4.9.2*/ … … 278 276 #endif 279 277 278 280 279 /** @} */ 281 280 … … 291 290 if (cSegs && paSegs) 292 291 { 293 pGcSgBuf-> pGcSegCur = paSegs[0].pGcSeg;292 pGcSgBuf->gcPhysCur = paSegs[0].gcPhys; 294 293 pGcSgBuf->cbSegLeft = paSegs[0].cbSeg; 295 294 } 296 295 else 297 296 { 298 pGcSgBuf-> pGcSegCur = 0;297 pGcSgBuf->gcPhysCur = 0; 299 298 pGcSgBuf->cbSegLeft = 0; 300 299 } … … 316 315 317 316 AssertMsg( pGcSgBuf->cbSegLeft <= 128 * _1M 318 && (RTGCPHYS)pGcSgBuf-> pGcSegCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg319 && (RTGCPHYS)pGcSgBuf-> pGcSegCur + pGcSgBuf->cbSegLeft <=320 (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg]. pGcSeg+ pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,321 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf-> pGcSegCur=%p pGcSgBuf->cbSegLeft=%zd "322 "pGcSgBuf->paSegs[%d]. pGcSeg=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",323 pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf-> pGcSegCur, pGcSgBuf->cbSegLeft,324 pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg]. pGcSeg, pGcSgBuf->idxSeg,317 && (RTGCPHYS)pGcSgBuf->gcPhysCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys 318 && (RTGCPHYS)pGcSgBuf->gcPhysCur + pGcSgBuf->cbSegLeft <= 319 (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg, 320 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->gcPhysCur=%p pGcSgBuf->cbSegLeft=%zd " 321 "pGcSgBuf->paSegs[%d].gcPhys=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n", 322 pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->gcPhysCur, pGcSgBuf->cbSegLeft, 323 pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys, pGcSgBuf->idxSeg, 325 324 pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg)); 326 325 327 326 cbData = RT_MIN(*pcbData, pGcSgBuf->cbSegLeft); 328 pGcBuf = pGcSgBuf-> pGcSegCur;327 pGcBuf = pGcSgBuf->gcPhysCur; 329 328 pGcSgBuf->cbSegLeft -= cbData; 330 329 if (!pGcSgBuf->cbSegLeft) … … 334 333 if (pGcSgBuf->idxSeg < pGcSgBuf->cSegs) 335 334 { 336 pGcSgBuf-> pGcSegCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg;335 pGcSgBuf->gcPhysCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys; 337 336 pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg; 338 337 } … … 340 339 } 341 340 else 342 pGcSgBuf-> pGcSegCur = pGcSgBuf->pGcSegCur + cbData;341 pGcSgBuf->gcPhysCur = pGcSgBuf->gcPhysCur + cbData; 343 342 344 343 return pGcBuf; … … 352 351 if (pGcSgBuf->cSegs) 353 352 { 354 pGcSgBuf-> pGcSegCur = pGcSgBuf->paSegs[0].pGcSeg;353 pGcSgBuf->gcPhysCur = pGcSgBuf->paSegs[0].gcPhys; 355 354 pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[0].cbSeg; 356 355 } 357 356 else 358 357 { 359 pGcSgBuf-> pGcSegCur = 0;358 pGcSgBuf->gcPhysCur = 0; 360 359 pGcSgBuf->cbSegLeft = 0; 361 360 } … … 541 540 #endif /* IN_RING3 */ 542 541 543 /**544 * See API comments in header file for description545 */546 int virtioQueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue)547 {548 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));549 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];550 551 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue],552 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);553 554 if (virtioCoreQueueIsEmpty(pVirtio->pDevIns, pVirtio, idxQueue))555 return VERR_NOT_AVAILABLE;556 557 Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx));558 pVirtq->uAvailIdx++;559 560 return VINF_SUCCESS;561 }562 542 563 543 /** … … 648 628 } 649 629 650 pSeg-> pGcSeg= desc.GCPhysBuf;630 pSeg->gcPhys = desc.GCPhysBuf; 651 631 pSeg->cbSeg = desc.cb; 652 632 … … 679 659 } 680 660 661 /* 662 * Notifies guest (via ISR or MSI-X) of device configuration change 663 * 664 * @param pVirtio Pointer to the shared virtio state. 665 */ 666 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio) 667 { 668 virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false); 669 670 } 671 672 /** 673 * Enable or Disable notification for the specified queue 674 * 675 * @param pVirtio Pointer to the shared virtio state. 676 * @param idxQueue Queue number 677 * @param fEnabled Selects notification mode (enabled or disabled) 678 */ 679 void virtioCoreQueueSetNotify(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled) 680 { 681 uint16_t fFlags = virtioReadUsedFlags(pVirtio->pDevIns, pVirtio, idxQueue); 682 683 if (fEnabled) 684 fFlags &= ~ VIRTQ_USED_F_NO_NOTIFY; 685 else 686 fFlags |= VIRTQ_USED_F_NO_NOTIFY; 687 688 virtioWriteUsedFlags(pVirtio->pDevIns, pVirtio, idxQueue, fFlags); 689 } 690 691 692 /** 693 * Initiate orderly reset procedure. This is an exposed API for clients that might need it. 694 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2) 695 * 696 * @param pVirtio Pointer to the virtio state. 697 */ 698 void virtioCoreResetAll(PVIRTIOCORE pVirtio) 699 { 700 LogFunc(("\n")); 701 pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET; 702 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 703 { 704 pVirtio->fGenUpdatePending = true; 705 virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */); 706 } 707 } 708 /** 709 * Get count of new (e.g. pending) elements in available ring. 710 * 711 * @param pDevIns The device instance. 712 * @param pVirtio Pointer to the shared virtio state. 713 * @param idxQueue Queue number 714 * 715 * @returns how many entries have been added to ring as a delta of the consumer's 716 * avail index and the queue's guest-side current avail index. 717 */ 718 int virtioCoreR3QueuePendingCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 719 { 720 uint16_t uAvailRingIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, idxQueue); 721 uint16_t uNextAvailIdx = pVirtio->virtqState[idxQueue].uAvailIdx; 722 int16_t iDelta = uAvailRingIdx - uNextAvailIdx; 723 uint16_t uDelta = uAvailRingIdx - uNextAvailIdx; 724 return iDelta >= 0 ? uDelta : VIRTQ_MAX_CNT + uDelta; 725 } 681 726 /** 682 727 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor 683 * chain into its OUT (to device) and IN to guest components. 728 * chain into its OUT (to device) and IN to guest components, but does NOT remove it from 729 * the 'avail' queue. I.e. doesn't advance the index. This can be used with virtioQueueSkip(), 730 * which *does* advance the avail index. Together they facilitate a mechanism that allows 731 * work with a queue element (descriptor chain) to be aborted if necessary, by not advancing 732 * the pointer, or, upon success calling the skip function (above) to move to the next element. 684 733 * 685 734 * Additionally it converts the OUT desc chain data to a contiguous virtual … … 691 740 * @param pVirtio Pointer to the shared virtio state. 692 741 * @param idxQueue Queue number 693 * @param fRemove flags whether to remove desc chain from queue (false = peek)694 742 * @param ppDescChain Address to store pointer to descriptor chain that contains the 695 743 * pre-processed transaction information pulled from the virtq. 744 * 745 * @returns VBox status code: 746 * @retval VINF_SUCCESS Success 747 * @retval VERR_INVALID_STATE VirtIO not in ready state (asserted). 748 * @retval VERR_NOT_AVAILABLE If the queue is empty. 749 */ 750 751 int virtioCoreR3QueuePeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 752 PPVIRTIO_DESC_CHAIN_T ppDescChain) 753 { 754 return virtioCoreR3QueueGet(pDevIns, pVirtio, idxQueue, ppDescChain, false); 755 } 756 757 /** 758 * Skip the next entry in the specified queue (typically used with virtioCoreR3QueuePeek()) 759 * 760 * @param pVirtio Pointer to the virtio state. 761 * @param idxQueue Index of queue 762 */ 763 int virtioCoreR3QueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue) 764 { 765 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState)); 766 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue]; 767 768 AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue], 769 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 770 771 if (virtioCoreQueueIsEmpty(pVirtio->pDevIns, pVirtio, idxQueue)) 772 return VERR_NOT_AVAILABLE; 773 774 Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx)); 775 pVirtq->uAvailIdx++; 776 777 return VINF_SUCCESS; 778 } 779 780 /** 781 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor 782 * chain into its OUT (to device) and IN to guest components. 783 * 784 * Additionally it converts the OUT desc chain data to a contiguous virtual 785 * memory buffer for easy consumption by the caller. The caller must return the 786 * descriptor chain pointer via virtioCoreR3QueuePut() and then call virtioCoreQueueSync() 787 * at some point to return the data to the guest and complete the transaction. 788 * 789 * @param pDevIns The device instance. 790 * @param pVirtio Pointer to the shared virtio state. 791 * @param idxQueue Queue number 792 * @param ppDescChain Address to store pointer to descriptor chain that contains the 793 * pre-processed transaction information pulled from the virtq. 794 * @param fRemove flags whether to remove desc chain from queue (false = peek) 696 795 * 697 796 * @returns VBox status code: … … 734 833 * @param idxQueue Queue number 735 834 * 736 * @param pSgVirtReturn Points to scatter-gather buffer of virtual memory835 * @param pSgVirtReturn Points to scatter-gather buffer of virtual memory 737 836 * segments the caller is returning to the guest. 738 837 * … … 768 867 769 868 size_t cbCopy = 0; 770 size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn); 771 virtioCoreSgBufReset(pSgPhysReturn); /* Reset ptr because req data may have already been written */ 772 while (cbRemain) 773 { 774 PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg]; 775 uint64_t dstSgStart = (uint64_t)paSeg->pGcSeg; 776 uint64_t dstSgLen = (uint64_t)paSeg->cbSeg; 777 uint64_t dstSgCur = (uint64_t)pSgPhysReturn->pGcSegCur; 778 cbCopy = RT_MIN((uint64_t)pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart)); 779 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->pGcSegCur, pSgVirtReturn->pvSegCur, cbCopy); 780 RTSgBufAdvance(pSgVirtReturn, cbCopy); 781 virtioCoreSgBufAdvance(pSgPhysReturn, cbCopy); 782 cbRemain -= cbCopy; 783 } 784 785 if (fFence) 786 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */ 869 870 if (pSgVirtReturn) 871 { 872 size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn); 873 virtioCoreSgBufReset(pSgPhysReturn); /* Reset ptr because req data may have already been written */ 874 while (cbRemain) 875 { 876 PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg]; 877 uint64_t dstSgStart = (uint64_t)paSeg->gcPhys; 878 uint64_t dstSgLen = (uint64_t)paSeg->cbSeg; 879 uint64_t dstSgCur = (uint64_t)pSgPhysReturn->gcPhysCur; 880 cbCopy = RT_MIN((uint64_t)pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart)); 881 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->gcPhysCur, pSgVirtReturn->pvSegCur, cbCopy); 882 RTSgBufAdvance(pSgVirtReturn, cbCopy); 883 virtioCoreSgBufAdvance(pSgPhysReturn, cbCopy); 884 cbRemain -= cbCopy; 885 } 886 887 if (fFence) 888 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */ 889 890 Assert(!(cbCopy >> 32)); 891 } 892 787 893 788 894 /* If this write-ahead crosses threshold where the driver wants to get an event flag it */ … … 790 896 if (pVirtq->uUsedIdx == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue)) 791 897 pVirtq->fEventThresholdReached = true; 792 793 Assert(!(cbCopy >> 32));794 898 795 899 /* … … 959 1063 else if (uMsixVector != VIRTIO_MSI_NO_VECTOR) 960 1064 PDMDevHlpPCISetIrq(pDevIns, pVirtio->uMsixConfig, PDM_IRQ_LEVEL_LOW); 961 }962 963 964 965 /**966 * Initiate orderly reset procedure. This is an exposed API for clients that might need it.967 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)968 */969 void virtioCoreResetAll(PVIRTIOCORE pVirtio)970 {971 LogFunc(("\n"));972 pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;973 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)974 {975 pVirtio->fGenUpdatePending = true;976 virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */);977 }978 1065 } 979 1066 … … 1394 1481 * 1395 1482 * This MMIO handler specifically supports the VIRTIO_PCI_CAP_PCI_CFG capability defined 1396 * in the VirtIO 1.0 specification, section 4.1.4.7, and as such is limited to cb == 1, cb == 2, or cb==4 type writes. 1483 * in the VirtIO 1.0 specification, section 4.1.4.7, and as such is limited 1484 * to cb == 1, cb == 2, or cb==4 type writes. 1397 1485 */ 1398 1486 static DECLCALLBACK(VBOXSTRICTRC) virtioMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb) -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r82151 r82863 71 71 typedef struct VIRTIOSGSEG /**< An S/G entry */ 72 72 { 73 RTGCPHYS pGcSeg; /**< Pointer to the segment buffer */73 RTGCPHYS gcPhys; /**< Pointer to the segment buffer */ 74 74 size_t cbSeg; /**< Size of the segment buffer */ 75 75 } VIRTIOSGSEG; … … 84 84 unsigned cSegs; /**< Number of segments */ 85 85 unsigned idxSeg; /**< Current segment we are in */ 86 RTGCPHYS pGcSegCur; /**< Ptr to byte within the current seg */86 RTGCPHYS gcPhysCur; /**< Ptr to byte within the current seg */ 87 87 size_t cbSegLeft; /**< # of bytes left in the current segment */ 88 88 } VIRTIOSGBUF; … … 377 377 uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain); 378 378 379 int virtioCoreR3QueuePeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 380 PPVIRTIO_DESC_CHAIN_T ppDescChain); 381 382 int virtioCoreR3QueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue); 383 379 384 int virtioCoreR3QueueGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 380 385 PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove); 386 381 387 int virtioCoreR3QueuePut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn, 382 388 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence); 389 390 int virtioCoreR3QueuePendingCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 383 391 int virtioCoreQueueSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 384 392 bool virtioCoreQueueIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 385 393 void virtioCoreQueueEnable(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled); 386 387 /** 388 * Skip the next entry in the specified queue 389 * 390 * @param pVirtio Pointer to the virtio state. 391 * @param idxQueue Index of queue 392 * 393 */ 394 int virtioQueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue); 395 396 /** 397 * Reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2) 398 * 399 * @param pVirtio Pointer to the virtio state. 400 */ 394 void virtioCoreQueueSetNotify(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled); 395 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio); 401 396 void virtioCoreResetAll(PVIRTIOCORE pVirtio); 402 397
Note:
See TracChangeset
for help on using the changeset viewer.