Changeset 92939 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Dec 15, 2021 3:51:28 PM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 148914
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
r92091 r92939 24 24 */ 25 25 26 27 /********************************************************************************************************************************* 28 * Header Files * 29 *********************************************************************************************************************************/ 26 /******************************************************************************************************************************* 27 * Header Files * 28 ***************************************************************************************************************************** **/ 30 29 //#define LOG_GROUP LOG_GROUP_DRV_NET 31 30 #define LOG_GROUP LOG_GROUP_DEV_VIRTIO … … 45 44 #include <VBox/version.h> 46 45 #include <VBox/log.h> 46 47 47 48 48 #ifdef IN_RING3 … … 59 59 #include "VBoxDD.h" 60 60 61 #define LUN0 0 61 #define VIRTIONET_TRANSITIONAL_ENABLE_FLAG 1 /** < If set behave as VirtIO "transitional" device */ 62 63 /** The current saved state version for the virtio core. */ 64 #define VIRTIONET_SAVEDSTATE_VERSION UINT32_C(1) 65 #define VIRTIONET_SAVEDSTATE_VERSION_3_1_BETA1_LEGACY UINT32_C(1) /**< Grandfathered in from DevVirtioNet.cpp */ 66 #define VIRTIONET_SAVEDSTATE_VERSION_LEGACY UINT32_C(2) /**< Grandfathered in from DevVirtioNet.cpp */ 67 #define VIRTIONET_VERSION_MARKER_MAC_ADDR { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /** SSM handling */ 68 69 /* 70 * Glossary of networking acronyms used in feature names below: 71 * 72 * GSO = Generic Segmentation Offload 73 * TSO = TCP Segmentation Offload 74 * UFO = UDP Fragmentation Offload 75 * ECN = Explicit Congestion Notification 76 */ 62 77 63 78 /** @name VirtIO 1.0 NET Host feature bits (See VirtIO 1.0 specification, Section 5.6.3) … … 88 103 static const VIRTIO_FEATURES_LIST s_aDevSpecificFeatures[] = 89 104 { 90 { VIRTIONET_F_CSUM, " CSUM Host handles packets with partial checksum.\n" }, 105 { VIRTIONET_F_STATUS, " STATUS Configuration status field is available.\n" }, 106 { VIRTIONET_F_MAC, " MAC Host has given MAC address.\n" }, 107 { VIRTIONET_F_CTRL_VQ, " CTRL_VQ Control channel is available.\n" }, 108 { VIRTIONET_F_CTRL_MAC_ADDR, " CTRL_MAC_ADDR Set MAC address through control channel.\n" }, 109 { VIRTIONET_F_CTRL_RX, " CTRL_RX Control channel RX mode support.\n" }, 110 { VIRTIONET_F_CTRL_VLAN, " CTRL_VLAN Control channel VLAN filtering.\n" }, 111 { VIRTIONET_F_CTRL_GUEST_OFFLOADS, " CTRL_GUEST_OFFLOADS Control channel offloads reconfiguration support.\n" }, 91 112 { VIRTIONET_F_GUEST_CSUM, " GUEST_CSUM Guest handles packets with partial checksum.\n" }, 92 { VIRTIONET_F_CTRL_GUEST_OFFLOADS, " CTRL_GUEST_OFFLOADS Control channel offloads reconfiguration support.\n" }, 93 { VIRTIONET_F_MAC, " MAC Host has given MAC address.\n" }, 113 { VIRTIONET_F_GUEST_ANNOUNCE, " GUEST_ANNOUNCE Guest can send gratuitous packets.\n" }, 94 114 { VIRTIONET_F_GUEST_TSO4, " GUEST_TSO4 Guest can receive TSOv4.\n" }, 95 115 { VIRTIONET_F_GUEST_TSO6, " GUEST_TSO6 Guest can receive TSOv6.\n" }, … … 100 120 { VIRTIONET_F_HOST_ECN, " HOST_ECN Host can receive TSO with ECN.\n" }, 101 121 { VIRTIONET_F_HOST_UFO, " HOST_UFO Host can receive UFO.\n" }, 122 { VIRTIONET_F_MQ, " MQ Host supports multiqueue with automatic receive steering.\n" }, 123 { VIRTIONET_F_CSUM, " CSUM Host handles packets with partial checksum.\n" }, 102 124 { VIRTIONET_F_MRG_RXBUF, " MRG_RXBUF Guest can merge receive buffers.\n" }, 103 { VIRTIONET_F_STATUS, " STATUS Configuration status field is available.\n" },104 { VIRTIONET_F_CTRL_VQ, " CTRL_VQ Control channel is available.\n" },105 { VIRTIONET_F_CTRL_RX, " CTRL_RX Control channel RX mode support.\n" },106 { VIRTIONET_F_CTRL_VLAN, " CTRL_VLAN Control channel VLAN filtering.\n" },107 { VIRTIONET_F_GUEST_ANNOUNCE, " GUEST_ANNOUNCE Guest can send gratuitous packets.\n" },108 { VIRTIONET_F_MQ, " MQ Host supports multiqueue with automatic receive steering.\n" },109 { VIRTIONET_F_CTRL_MAC_ADDR, " CTRL_MAC_ADDR Set MAC address through control channel.\n" },110 125 }; 111 112 126 113 127 #ifdef VIRTIONET_WITH_GSO … … 135 149 | VIRTIONET_F_MRG_RXBUF 136 150 137 /*138 * Glossary of networking acronyms used in the previous bit definitions:139 *140 * GSO = Generic Segmentation Offload141 * TSO = TCP Segmentation Offload142 * UFO = UDP Fragmentation Offload143 * ECN = Explicit Congestion Notification144 */145 146 151 #define FEATURE_ENABLED(feature) RT_BOOL(!!(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)) 147 152 #define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature)) 148 153 #define FEATURE_OFFERED(feature) VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature 149 154 150 #define VIRTIONET_SAVED_STATE_VERSION UINT32_C(1)151 152 155 #if FEATURE_OFFERED(MQ) 153 # define VIRTIONET_MAX_QPAIRS 1000 /* Instance data doesn't allow an array with VIRTIONET_CTRL_MQ_VQ_PAIRS_MAX entries */ 156 /* Instance data doesn't allow an array large enough to contain VIRTIONET_CTRL_MQ_VQ_PAIRS_MAX entries */ 157 # define VIRTIONET_MAX_QPAIRS 1 /* This should be increased at some point and made to work */ 154 158 #else 155 # define VIRTIONET_MAX_QPAIRS VIRTIONET_CTRL_MQ_VQ_PAIRS_MIN 159 # define VIRTIONET_MAX_QPAIRS VIRTIONET_CTRL_MQ_VQ_PAIRS_MIN /* default, VirtIO 1.0, 5.1.6.5.5 */ 156 160 #endif 157 161 158 #define VIRTIONET_MAX_WORKERS VIRTIONET_MAX_QPAIRS 162 #define VIRTIONET_CTRL_MQ_VQ_PAIRS 64 163 #define VIRTIONET_MAX_WORKERS VIRTIONET_MAX_QPAIRS + 1 159 164 #define VIRTIONET_MAX_VIRTQS (VIRTIONET_MAX_QPAIRS * 2 + 1) 160 165 #define VIRTIONET_MAX_FRAME_SIZE 65535 + 18 /**< Max IP pkt size + Eth. header w/VLAN tag */ 161 #define VIRTIONET_MAC_FILTER_LEN 32162 #define VIRTIONET_MAX_VLAN_ID (1 << 12)166 #define VIRTIONET_MAC_FILTER_LEN 64 167 #define VIRTIONET_MAX_VLAN_ID 4096 163 168 #define VIRTIONET_RX_SEG_COUNT 32 164 169 … … 166 171 #define CBVIRTQNAME(uVirtqNbr) RTStrNLen(VIRTQNAME(uVirtqNbr), sizeof(VIRTQNAME(uVirtqNbr))) 167 172 168 /* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */169 173 #define IS_TX_VIRTQ(n) ((n) != CTRLQIDX && ((n) & 1)) 170 174 #define IS_RX_VIRTQ(n) ((n) != CTRLQIDX && !IS_TX_VIRTQ(n)) 171 175 #define IS_CTRL_VIRTQ(n) ((n) == CTRLQIDX) 176 177 /* 178 * Macros to calculate queue type-pecific index number regardless of scale. VirtIO 1.0, 5.1.2 179 */ 172 180 #define RXQIDX(qPairIdx) (qPairIdx * 2) 173 181 #define TXQIDX(qPairIdx) (RXQIDX(qPairIdx) + 1) … … 189 197 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, uVirtqNbr) \ 190 198 (virtioCoreVirtqAvailBufCount(pDevIns, pVirtio, uVirtqNbr) == 0) 191 192 199 193 200 #define PCI_DEVICE_ID_VIRTIONET_HOST 0x1000 /**< VirtIO transitional device ID for network card */ … … 198 205 199 206 /** 200 * Virt io Net Host Device device-specific configuration (VirtIO 1.0, 5.1.4)201 * VBox VirtIO core issues callback to this VirtIO device-specific implementation to handle202 * MMIO accesses to device-specific configuration parameters.207 * VirtIO Network (virtio-net) device-specific configuration subregion (VirtIO 1.0, 5.1.4) 208 * Guest MMIO is processed through callback to VirtIO core which forwards references to network configuration 209 * fields to this device-specific code through a callback. 203 210 */ 204 211 #pragma pack(1) … … 260 267 261 268 /* Command entry fAck values */ 262 #define VIRTIONET_OK 0 263 #define VIRTIONET_ERROR 1 269 #define VIRTIONET_OK 0 /**< Internal success status */ 270 #define VIRTIONET_ERROR 1 /**< Internal failure status */ 264 271 265 272 /** @name Control virtq: Receive filtering flags (VirtIO 1.0, 5.1.6.5.1) … … 315 322 * @{ */ 316 323 #define VIRTIONET_CTRL_GUEST_OFFLOADS 5 /**< Control class: Offloads state configuration */ 317 #define VIRTIONET_CTRL_GUEST_OFFLOADS_SET 0 /** Apply new offloads configuration*/324 #define VIRTIONET_CTRL_GUEST_OFFLOADS_SET 0 /**< Apply new offloads configuration */ 318 325 /** @} */ 319 326 320 327 typedef enum VIRTIONETPKTHDRTYPE 321 328 { 322 kVirtioNetModernPktHdr_1_0 = 0, 323 kVirtioNetLegacyPktHdr = 1, 324 kVirtioNetLegacyPktHdrWithoutMrgRx = 2, 329 kVirtioNetUninitializedPktHdrType = 0, /**< Uninitialized (default) packet header type */ 330 kVirtioNetModernPktHdrWithoutMrgRx = 1, /**< Packets should not be merged (modern driver) */ 331 kVirtioNetModernPktHdrWithMrgRx = 2, /**< Packets should be merged (modern driver) */ 332 kVirtioNetLegacyPktHdrWithoutMrgRx = 3, /**< Packets should not be merged (legacy driver) */ 333 kVirtioNetLegacyPktHdrWithMrgRx = 4, /**< Packets should be merged (legacy driver) */ 325 334 kVirtioNetFor32BitHack = 0x7fffffff 326 335 } VIRTIONETPKTHDRTYPE; … … 336 345 uint16_t uIdx; /**< Index of this queue */ 337 346 uint16_t align; 338 char szName[VIRTIO_MAX_VIRTQ_NAME_SIZE]; /**< Virtq name */339 347 bool fCtlVirtq; /**< If set this queue is the control queue */ 340 348 bool fHasWorker; /**< If set this queue has an associated worker */ 341 349 bool fAttachedToVirtioCore; /**< Set if queue attached to virtio core */ 342 uint8_t pad;350 char szName[VIRTIO_MAX_VIRTQ_NAME_SIZE]; /**< Virtq name */ 343 351 } VIRTIONETVIRTQ, *PVIRTIONETVIRTQ; 344 352 … … 407 415 uint16_t cWorkers; 408 416 409 /** Alig hnment */417 /** Alignment */ 410 418 uint16_t alignment; 411 419 … … 413 421 uint32_t uIsTransmitting; 414 422 415 /** virtio-net-1-dot-0(in milliseconds). */423 /** Link up delay (in milliseconds). */ 416 424 uint32_t cMsLinkUpDelay; 417 425 … … 479 487 bool fCableConnected; 480 488 481 /** True if guest has not reported modern virtio driver */ 482 bool fIsLegacy; 489 /** True if this device should offer legacy virtio support to the guest */ 490 bool fOfferLegacy; 491 483 492 /** @name Statistic 484 493 * @{ */ … … 550 559 } VIRTIONETR3; 551 560 552 553 561 /** Pointer to the ring-3 state of the VirtIO Host NET device. */ 554 562 typedef VIRTIONETR3 *PVIRTIONETR3; … … 565 573 typedef VIRTIONETR0 *PVIRTIONETR0; 566 574 567 568 575 /** 569 576 * VirtIO Host NET device state, raw-mode edition. … … 577 584 typedef VIRTIONETRC *PVIRTIONETRC; 578 585 579 580 586 /** @typedef VIRTIONETCC 581 587 * The instance data for the current context. */ … … 590 596 static int virtioNetR3CreateWorkerThreads(PPDMDEVINS, PVIRTIONET, PVIRTIONETCC); 591 597 598 /** 599 * Helper function used when logging state of a VM thread. 600 * 601 * @param Thread 602 * 603 * @return Associated name of thread as a pointer to a zero-terminated string. 604 */ 592 605 DECLINLINE(const char *) virtioNetThreadStateName(PPDMTHREAD pThread) 593 606 { … … 620 633 621 634 /** 622 * Wakeup the RX thread.635 * Wakeup PDM managed downstream (e.g. hierarchically inferior device's) RX thread 623 636 */ 624 637 static void virtioNetWakeupRxBufWaiter(PPDMDEVINS pDevIns) … … 638 651 639 652 /** 653 * Guest notifying us of its activity with a queue. Figure out which queue and respond accordingly. 654 * 640 655 * @callback_method_impl{VIRTIOCORER0,pfnVirtqNotified} 641 656 */ … … 662 677 } 663 678 else 664 Log10Func(("%s \n\n***WARNING: %s notified but no empty bufs added by guest! (skip notifying of leaf device)\n\n",679 Log10Func(("%s \n\n***WARNING: %s notified but no empty bufs added by guest! (skip leaf dev. notification)\n\n", 665 680 pThis->szInst, pVirtq->szName)); 666 681 } … … 678 693 } 679 694 else 680 {681 695 Log10Func(("[%s] %s has available buffers - worker already awake\n", pThis->szInst, pVirtq->szName)); 682 }683 696 } 684 697 else 685 {686 698 Log10Func(("[%s] %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName)); 687 }688 699 } 689 700 else … … 706 717 } 707 718 708 709 DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis) 710 { 711 RTStrCopy(pThis->aVirtqs[CTRLQIDX].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "controlq"); 712 for (uint16_t qPairIdx = pThis->cInitializedVirtqPairs; qPairIdx < pThis->cVirtqPairs; qPairIdx++) 713 { 714 RTStrPrintf(pThis->aVirtqs[RXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "receiveq<%d>", qPairIdx); 715 RTStrPrintf(pThis->aVirtqs[TXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "transmitq<%d>", qPairIdx); 719 /** 720 * Set queue names, distinguishing between modern or legacy mode. 721 * 722 * @note This makes it obvious during logging which mode this transitional device is 723 * operating in, legacy or modern. 724 * 725 * @param pThis Device specific device state 726 * @param fLegacy (input) true if running in legacy mode 727 * false if running in modern mode 728 */ 729 DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis, uint32_t fLegacy) 730 { 731 RTStrCopy(pThis->aVirtqs[CTRLQIDX].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, fLegacy ? "legacy-ctrlq" : " modern-ctrlq"); 732 for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++) 733 { 734 RTStrPrintf(pThis->aVirtqs[RXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "%s-recvq<%d>", fLegacy ? "legacy" : "modern", qPairIdx); 735 RTStrPrintf(pThis->aVirtqs[TXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "%s-xmitq<%d>", fLegacy ? "legacy" : "modern", qPairIdx); 716 736 } 717 737 } … … 727 747 DECLINLINE(void) virtioNetR3PacketDump(PVIRTIONET pThis, const uint8_t *pbPacket, size_t cb, const char *pszText) 728 748 { 749 #ifdef LOG_ENABLED 729 750 if (!LogIs12Enabled()) 730 751 return; 731 752 #endif 732 753 vboxEthPacketDump(pThis->szInst, pszText, pbPacket, (uint32_t)cb); 733 754 } 734 735 755 736 756 #ifdef LOG_ENABLED … … 742 762 if (pRxPktHdr) 743 763 { 744 LogFunc(("-------------------------------------------------------------------\n")); 764 LogFunc(("%*c\nrxPktHdr\n" 765 " uFlags ......... %2.2x\n uGsoType ....... %2.2x\n uHdrLen ........ %4.4x\n" 766 " uGsoSize ....... %4.4x\n uChksumStart ... %4.4x\n uChksumOffset .. %4.4x\n", 767 60, ' ', pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize, 768 pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset)); 745 769 if (!virtioCoreIsLegacyMode(&pThis->Virtio) || FEATURE_ENABLED(MRG_RXBUF)) 746 LogFunc(("rxPktHdr\n" 747 " uFlags ......... %2.2x\n uGsoType ....... %2.2x\n uHdrLen ........ %4.4x\n" 748 " uGsoSize ....... %4.4x\n uChksumStart ... %4.4x\n uChksumOffset .. %4.4x\n" 749 " uNumBuffers .... %4.4x\n", 750 pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize, 751 pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers)); 752 else 753 LogFunc(("rxPktHdr\n" 754 " uFlags ......... %2.2x\n uGsoType ....... %2.2x\n uHdrLen ........ %4.4x\n" 755 " uGsoSize ....... %4.4x\n uChksumStart ... %4.4x\n uChksumOffset .. %4.4x\n", 756 pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize, 757 pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset)); 770 LogFunc((" uNumBuffers .... %4.4x\n", pRxPktHdr->uNumBuffers)); 758 771 virtioCoreHexDump((uint8_t *)pRxPktHdr, sizeof(VIRTIONETPKTHDR), 0, "Dump of virtual rPktHdr"); 759 772 } 760 773 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 761 774 LogFunc((". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n")); 762 763 775 virtioCoreGCPhysHexDump(pDevIns, GCPhysRxBuf, cbRxBuf, 0, "Phys Mem Dump of Rx pkt"); 764 LogFunc((" -------------------------------------------------------------------\n"));776 LogFunc(("%*c", 60, '-')); 765 777 } 766 778 … … 852 864 if (fAll || fPointers) 853 865 { 854 pHlp->pfnPrintf(pHlp, "Internal Pointers :\n\n");866 pHlp->pfnPrintf(pHlp, "Internal Pointers (for instance \"%s\"):\n\n", pThis->szInst); 855 867 pHlp->pfnPrintf(pHlp, " pDevIns ................... %p\n", pDevIns); 868 pHlp->pfnPrintf(pHlp, " PVIRTIOCORE ............... %p\n", &pThis->Virtio); 856 869 pHlp->pfnPrintf(pHlp, " PVIRTIONET ................ %p\n", pThis); 857 870 pHlp->pfnPrintf(pHlp, " PVIRTIONETCC .............. %p\n", pThisCC); 871 pHlp->pfnPrintf(pHlp, " VIRTIONETVIRTQ[] .......... %p\n", pThis->aVirtqs); 858 872 pHlp->pfnPrintf(pHlp, " pDrvBase .................. %p\n", pThisCC->pDrvBase); 859 873 pHlp->pfnPrintf(pHlp, " pDrv ...................... %p\n", pThisCC->pDrv); … … 872 886 pHlp->pfnPrintf(pHlp, "Misc state\n"); 873 887 pHlp->pfnPrintf(pHlp, "\n"); 888 pHlp->pfnPrintf(pHlp, " fOfferLegacy .............. %d\n", pThis->fOfferLegacy); 874 889 pHlp->pfnPrintf(pHlp, " fVirtioReady .............. %d\n", pThis->fVirtioReady); 890 pHlp->pfnPrintf(pHlp, " fResetting ................ %d\n", pThis->fResetting); 875 891 pHlp->pfnPrintf(pHlp, " fGenUpdatePending ......... %d\n", pThis->Virtio.fGenUpdatePending); 876 892 pHlp->pfnPrintf(pHlp, " fMsiSupport ............... %d\n", pThis->Virtio.fMsiSupport); … … 929 945 } 930 946 931 /* 932 * Checks whether negotiated features have required flag combinations. 933 * See VirtIO 1.0 specification, Section 5.1.3.1 */ 947 /** 948 * Checks whether certain mutually dependent negotiated features are clustered in required combinations. 949 * 950 * @note See VirtIO 1.0 spec, Section 5.1.3.1 951 * 952 * @param fFeatures Bitmask of negotiated features to evaluate 953 * 954 * @returns true if valid feature combination(s) found. 955 * false if non-valid feature set. 956 */ 934 957 DECLINLINE(bool) virtioNetValidateRequiredFeatures(uint32_t fFeatures) 935 958 { … … 969 992 } 970 993 994 /** 995 * Read or write device-specific configuration parameters. 996 * This is called by VirtIO core code a guest-initiated MMIO access is made to access device-specific 997 * configuration 998 * 999 * @note See VirtIO 1.0 spec, 2.3 Device Configuration Space 1000 * 1001 * @param pThis Pointer to device-specific state 1002 * @param uOffsetOfAccess Offset (within VIRTIONET_CONFIG_T) 1003 * @param pv Pointer to data to read or write 1004 * @param cb Number of bytes to read or write 1005 * @param fWrite True if writing, false if reading 1006 * 1007 * @returns VINF_SUCCESS if successful, or VINF_IOM_MMIO_UNUSED if fails (bad offset or size) 1008 */ 971 1009 static int virtioNetR3DevCfgAccess(PVIRTIONET pThis, uint32_t uOffsetOfAccess, void *pv, uint32_t cb, bool fWrite) 972 1010 { … … 1017 1055 } 1018 1056 1057 static int virtioNetR3VirtqDestroy(PVIRTIOCORE pVirtio, PVIRTIONETVIRTQ pVirtq) 1058 { 1059 PVIRTIONET pThis = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio); 1060 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pVirtio->pDevInsR3, PVIRTIONETCC); 1061 PVIRTIONETWORKER pWorker = &pThis->aWorkers[pVirtq->uIdx]; 1062 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[pVirtq->uIdx]; 1063 1064 int rc, rcThread; 1065 Log10Func(("[%s] Destroying \"%s\"", pThis->szInst, pVirtq->szName)); 1066 if (pVirtq->fHasWorker) 1067 { 1068 Log10((" and its worker")); 1069 rc = PDMDevHlpSUPSemEventClose(pVirtio->pDevInsR3, pWorker->hEvtProcess); 1070 AssertRCReturn(rc, rc); 1071 pWorker->hEvtProcess = 0; 1072 rc = PDMDevHlpThreadDestroy(pVirtio->pDevInsR3, pWorkerR3->pThread, &rcThread); 1073 AssertRCReturn(rc, rc); 1074 pWorkerR3->pThread = 0; 1075 pVirtq->fHasWorker = false; 1076 } 1077 pWorker->fAssigned = false; 1078 pVirtq->fCtlVirtq = false; 1079 Log10(("\n")); 1080 return rc; 1081 } 1082 1019 1083 1020 1084 /********************************************************************************************************************************* … … 1024 1088 /** 1025 1089 * @callback_method_impl{FNSSMDEVLOADEXEC} 1026 */ 1027 static DECLCALLBACK(int) virtioNetR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 1090 * 1091 * @note: This is included to accept and migrate VMs that had used the original VirtualBox legacy-only virtio-net (network card) 1092 * controller device emulator ("DevVirtioNet.cpp") to work with this superset of VirtIO compatibility known 1093 * as a transitional device (see PDM-invoked device constructor comments for more information) 1094 */ 1095 static DECLCALLBACK(int) virtioNetR3LegacyDeviceLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass, 1096 RTMAC uMacLoaded) 1028 1097 { 1029 1098 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1030 1099 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1031 1100 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3; 1101 int rc; 1102 1103 Log7Func(("[%s] LOAD EXEC (LEGACY)!!\n", pThis->szInst)); 1104 1105 if (memcmp(&uMacLoaded.au8, &pThis->macConfigured.au8, sizeof(uMacLoaded)) 1106 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))) 1107 LogRelFunc(("[%s]: The mac address differs: config=%RTmac saved=%RTmac\n", 1108 pThis->szInst, &pThis->macConfigured, &uMacLoaded)); 1109 1110 if (uPass == SSM_PASS_FINAL) 1111 { 1112 /* Call the virtio core to have it load legacy device state */ 1113 rc = virtioCoreR3LegacyDeviceLoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, uVersion, VIRTIONET_SAVEDSTATE_VERSION_3_1_BETA1_LEGACY); 1114 AssertRCReturn(rc, rc); 1115 /* 1116 * Scan constructor-determined virtqs to determine if they are all valid-as-restored. 1117 * If so, nudge them with a signal, otherwise destroy the unusable queue(s) 1118 * to avoid tripping up the other queue processing logic. 1119 */ 1120 int cVirtqsToRemove = 0; 1121 for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) 1122 { 1123 PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr]; 1124 if (pVirtq->fHasWorker) 1125 { 1126 if (!virtioCoreR3VirtqIsEnabled(&pThis->Virtio, uVirtqNbr)) 1127 { 1128 virtioNetR3VirtqDestroy(&pThis->Virtio, pVirtq); 1129 ++cVirtqsToRemove; 1130 } 1131 else 1132 { 1133 if (virtioCoreR3VirtqIsAttached(&pThis->Virtio, uVirtqNbr)) 1134 { 1135 Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName)); 1136 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[pVirtq->uIdx].hEvtProcess); 1137 AssertRCReturn(rc, rc); 1138 } 1139 } 1140 } 1141 } 1142 AssertMsg(cVirtqsToRemove < 2, ("Multiple unusable queues in saved state unexpected\n")); 1143 pThis->cVirtqs -= cVirtqsToRemove; 1144 1145 pThis->virtioNetConfig.uStatus = pThis->Virtio.fDeviceStatus; 1146 pThis->fVirtioReady = pThis->Virtio.fDeviceStatus & VIRTIO_STATUS_DRIVER_OK; 1147 1148 rc = pHlp->pfnSSMGetMem(pSSM, pThis->virtioNetConfig.uMacAddress.au8, sizeof(pThis->virtioNetConfig.uMacAddress)); 1149 AssertRCReturn(rc, rc); 1150 1151 if (uVersion > VIRTIONET_SAVEDSTATE_VERSION_3_1_BETA1_LEGACY) 1152 { 1153 rc = pHlp->pfnSSMGetU8( pSSM, &pThis->fPromiscuous); 1154 AssertRCReturn(rc, rc); 1155 rc = pHlp->pfnSSMGetU8( pSSM, &pThis->fAllMulticast); 1156 AssertRCReturn(rc, rc); 1157 /* 1158 * The 0.95 legacy virtio spec defines a control queue command VIRTIO_NET_CTRL_MAC_TABLE_SET, 1159 * wherein guest driver configures two variable length mac filter tables: A unicast filter, 1160 * and a multicast filter. However original VBox virtio-net saved both sets of filter entries 1161 * in a single table, abandoning the distinction between unicast and multicast filters. It preserved 1162 * only *one* filter's table length, leaving no way to separate table back out into respective unicast 1163 * and multicast tables this device implementation preserves. Deduced from legacy code, the original 1164 * assumption was that the both MAC filters are whitelists that can be processed identically 1165 * (from the standpoint of a *single* host receiver), such that the distinction between unicast and 1166 * multicast doesn't matter in any one VM's context. Little choice here but to save the undifferentiated 1167 * unicast & multicast MACs to the unicast filter table and leave multicast table empty/unused. 1168 */ 1169 uint32_t cCombinedUnicastMulticastEntries; 1170 rc = pHlp->pfnSSMGetU32(pSSM, &cCombinedUnicastMulticastEntries); 1171 AssertRCReturn(rc, rc); 1172 AssertReturn(cCombinedUnicastMulticastEntries <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE); 1173 pThis->cUnicastFilterMacs = cCombinedUnicastMulticastEntries; 1174 rc = pHlp->pfnSSMGetMem(pSSM, pThis->aMacUnicastFilter, cCombinedUnicastMulticastEntries * sizeof(RTMAC)); 1175 AssertRCReturn(rc, rc); 1176 /* Zero-out the remainder of the Unicast/Multicast filter table */ 1177 memset(&pThis->aMacUnicastFilter[pThis->cUnicastFilterMacs], 0, VIRTIONET_MAC_FILTER_LEN * sizeof(RTMAC)); 1178 rc = pHlp->pfnSSMGetMem(pSSM, pThis->aVlanFilter, sizeof(pThis->aVlanFilter)); 1179 AssertRCReturn(rc, rc); 1180 } 1181 else 1182 { 1183 pThis->fAllMulticast = false; 1184 pThis->cUnicastFilterMacs = 0; 1185 memset(&pThis->aMacUnicastFilter, 0, VIRTIONET_MAC_FILTER_LEN * sizeof(RTMAC)); 1186 1187 memset(pThis->aVlanFilter, 0, sizeof(pThis->aVlanFilter)); 1188 1189 pThis->fPromiscuous = true; 1190 if (pThisCC->pDrv) 1191 pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true); 1192 } 1193 1194 /* 1195 * Log the restored VirtIO feature selection. 1196 */ 1197 pThis->fNegotiatedFeatures = virtioCoreGetNegotiatedFeatures(&pThis->Virtio); 1198 virtioCorePrintDeviceFeatures(&pThis->Virtio, NULL, s_aDevSpecificFeatures, RT_ELEMENTS(s_aDevSpecificFeatures)); 1199 1200 /* 1201 * Configure remaining transitional device parameters presumably or deductively 1202 * as these weren't part of the legacy device code thus it didn't save them to SSM 1203 */ 1204 pThis->fCableConnected = 1; 1205 pThis->fAllUnicast = 0; 1206 pThis->fNoMulticast = 0; 1207 pThis->fNoUnicast = 0; 1208 pThis->fNoBroadcast = 0; 1209 1210 /* Zero out the multicast table and count, all MAC filters, if any, are in the unicast filter table */ 1211 pThis->cMulticastFilterMacs = 0; 1212 memset(&pThis->aMacMulticastFilter, 0, VIRTIONET_MAC_FILTER_LEN * sizeof(RTMAC)); 1213 1214 } 1215 return VINF_SUCCESS; 1216 } 1217 1218 /** 1219 * @callback_method_impl{FNSSMDEVLOADEXEC} 1220 * 1221 * @note: This loads state saved by a Modern (VirtIO 1.0+) device, of which this transitional device is one, 1222 * and thus supports both legacy and modern guest virtio drivers. 1223 */ 1224 static DECLCALLBACK(int) virtioNetR3ModernDeviceLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 1225 { 1226 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1227 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1228 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3; 1229 int rc; 1032 1230 1033 1231 RT_NOREF(pThisCC); 1232 1233 RTMAC uMacLoaded, uVersionMarkerMac = VIRTIONET_VERSION_MARKER_MAC_ADDR; 1234 rc = pHlp->pfnSSMGetMem(pSSM, &uMacLoaded.au8, sizeof(uMacLoaded.au8)); 1235 AssertRCReturn(rc, rc); 1236 if (memcmp(&uMacLoaded.au8, uVersionMarkerMac.au8, sizeof(uVersionMarkerMac.au8))) 1237 { 1238 rc = virtioNetR3LegacyDeviceLoadExec(pDevIns, pSSM, uVersion, uPass, uMacLoaded); 1239 return rc; 1240 } 1241 1034 1242 Log7Func(("[%s] LOAD EXEC!!\n", pThis->szInst)); 1035 1243 1036 1244 AssertReturn(uPass == SSM_PASS_FINAL, VERR_SSM_UNEXPECTED_PASS); 1037 AssertLogRelMsgReturn(uVersion == VIRTIONET_SAVED _STATE_VERSION,1245 AssertLogRelMsgReturn(uVersion == VIRTIONET_SAVEDSTATE_VERSION, 1038 1246 ("uVersion=%u\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION); 1039 1247 1040 virtioNetR3SetVirtqNames(pThis );1248 virtioNetR3SetVirtqNames(pThis, false /* fLegacy */); 1041 1249 1042 1250 pHlp->pfnSSMGetU64( pSSM, &pThis->fNegotiatedFeatures); 1043 1251 1044 1252 pHlp->pfnSSMGetU16( pSSM, &pThis->cVirtqs); 1045 AssertReturn(pThis->cVirtqs <= (VIRTIONET_MAX_QPAIRS * 2), VERR_OUT_OF_RANGE); 1046 1253 AssertReturn(pThis->cVirtqs <= (VIRTIONET_MAX_QPAIRS * 2) + 1, VERR_OUT_OF_RANGE); 1047 1254 pHlp->pfnSSMGetU16( pSSM, &pThis->cWorkers); 1048 AssertReturn(pThis->cWorkers <= VIRTIONET_MAX_WORKERS, VERR_OUT_OF_RANGE); 1049 1255 AssertReturn(pThis->cWorkers <= VIRTIONET_MAX_WORKERS , VERR_OUT_OF_RANGE); 1050 1256 1051 1257 for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) 1052 pHlp->pfnSSMGetBool(pSSM, &pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore); 1053 1054 int rc; 1055 1056 if (uPass == SSM_PASS_FINAL) 1057 { 1058 1059 /* Load config area */ 1060 #if FEATURE_OFFERED(STATUS) 1061 /* config checks */ 1258 pHlp->pfnSSMGetBool(pSSM, &pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore); 1259 1260 /* Config checks */ 1062 1261 RTMAC macConfigured; 1063 1262 rc = pHlp->pfnSSMGetMem(pSSM, &macConfigured.au8, sizeof(macConfigured.au8)); … … 1065 1264 if (memcmp(&macConfigured.au8, &pThis->macConfigured.au8, sizeof(macConfigured.au8)) 1066 1265 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))) 1067 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", 1068 pThis->szInst, &pThis->macConfigured, &macConfigured)); 1266 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", 1267 pThis->szInst, &pThis->macConfigured, &macConfigured)); 1268 memcpy(pThis->virtioNetConfig.uMacAddress.au8, macConfigured.au8, sizeof(macConfigured.au8)); 1269 1270 #if FEATURE_OFFERED(STATUS) 1271 uint16_t fChkStatus; 1272 pHlp->pfnSSMGetU16( pSSM, &fChkStatus); 1273 if (fChkStatus == 0xffff) 1274 { 1275 /* Dummy value in saved state because status feature wasn't enabled at the time */ 1276 pThis->virtioNetConfig.uStatus = 0; /* VIRTIO_NET_S_ANNOUNCE disabled */ 1277 pThis->virtioNetConfig.uStatus = !!IS_LINK_UP(pThis); /* VIRTIO_NET_IS_LINK_UP (bit 0) */ 1278 } 1279 else 1280 pThis->virtioNetConfig.uStatus = fChkStatus; 1281 #else 1282 uint16_t fDiscard; 1283 pHlp->pfnSSMGetU16( pSSM, &fDiscard); 1069 1284 #endif 1070 1285 1071 1286 #if FEATURE_OFFERED(MQ) 1072 pHlp->pfnSSMGetU16( pSSM, &pThis->virtioNetConfig.uMaxVirtqPairs); 1287 uint16_t uCheckMaxVirtqPairs; 1288 pHlp->pfnSSMGetU16( pSSM, &uCheckMaxVirtqPairs); 1289 if (uCheckMaxVirtqPairs) 1290 pThis->virtioNetConfig.uMaxVirtqPairs = uCheckMaxVirtqPairs; 1291 else 1292 pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_CTRL_MQ_VQ_PAIRS; 1293 #else 1294 uint16_t fDiscard; 1295 pHlp->pfnSSMGetU16( pSSM, &fDiscard); 1073 1296 #endif 1074 /* Save device-specific part */ 1075 pHlp->pfnSSMGetBool( pSSM, &pThis->fCableConnected); 1076 pHlp->pfnSSMGetU8( pSSM, &pThis->fPromiscuous); 1077 pHlp->pfnSSMGetU8( pSSM, &pThis->fAllMulticast); 1078 pHlp->pfnSSMGetU8( pSSM, &pThis->fAllUnicast); 1079 pHlp->pfnSSMGetU8( pSSM, &pThis->fNoMulticast); 1080 pHlp->pfnSSMGetU8( pSSM, &pThis->fNoUnicast); 1081 pHlp->pfnSSMGetU8( pSSM, &pThis->fNoBroadcast); 1082 1083 pHlp->pfnSSMGetU32( pSSM, &pThis->cMulticastFilterMacs); 1084 AssertReturn(pThis->cMulticastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE); 1085 pHlp->pfnSSMGetMem( pSSM, pThis->aMacMulticastFilter, pThis->cMulticastFilterMacs * sizeof(RTMAC)); 1086 1087 if (pThis->cMulticastFilterMacs < VIRTIONET_MAC_FILTER_LEN) 1088 memset(&pThis->aMacMulticastFilter[pThis->cMulticastFilterMacs], 0, 1089 (VIRTIONET_MAC_FILTER_LEN - pThis->cMulticastFilterMacs) * sizeof(RTMAC)); 1090 1091 pHlp->pfnSSMGetU32( pSSM, &pThis->cUnicastFilterMacs); 1092 AssertReturn(pThis->cUnicastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE); 1093 pHlp->pfnSSMGetMem( pSSM, pThis->aMacUnicastFilter, pThis->cUnicastFilterMacs * sizeof(RTMAC)); 1094 1095 if (pThis->cUnicastFilterMacs < VIRTIONET_MAC_FILTER_LEN) 1096 memset(&pThis->aMacUnicastFilter[pThis->cUnicastFilterMacs], 0, 1097 (VIRTIONET_MAC_FILTER_LEN - pThis->cUnicastFilterMacs) * sizeof(RTMAC)); 1098 1099 rc = pHlp->pfnSSMGetMem(pSSM, pThis->aVlanFilter, sizeof(pThis->aVlanFilter)); 1100 AssertRCReturn(rc, rc); 1101 } 1102 1297 1298 /* Save device-specific part */ 1299 pHlp->pfnSSMGetBool( pSSM, &pThis->fCableConnected); 1300 pHlp->pfnSSMGetU8( pSSM, &pThis->fPromiscuous); 1301 pHlp->pfnSSMGetU8( pSSM, &pThis->fAllMulticast); 1302 pHlp->pfnSSMGetU8( pSSM, &pThis->fAllUnicast); 1303 pHlp->pfnSSMGetU8( pSSM, &pThis->fNoMulticast); 1304 pHlp->pfnSSMGetU8( pSSM, &pThis->fNoUnicast); 1305 pHlp->pfnSSMGetU8( pSSM, &pThis->fNoBroadcast); 1306 1307 pHlp->pfnSSMGetU32( pSSM, &pThis->cMulticastFilterMacs); 1308 AssertReturn(pThis->cMulticastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE); 1309 pHlp->pfnSSMGetMem( pSSM, pThis->aMacMulticastFilter, pThis->cMulticastFilterMacs * sizeof(RTMAC)); 1310 1311 if (pThis->cMulticastFilterMacs < VIRTIONET_MAC_FILTER_LEN) 1312 memset(&pThis->aMacMulticastFilter[pThis->cMulticastFilterMacs], 0, 1313 (VIRTIONET_MAC_FILTER_LEN - pThis->cMulticastFilterMacs) * sizeof(RTMAC)); 1314 1315 pHlp->pfnSSMGetU32( pSSM, &pThis->cUnicastFilterMacs); 1316 AssertReturn(pThis->cUnicastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE); 1317 pHlp->pfnSSMGetMem( pSSM, pThis->aMacUnicastFilter, pThis->cUnicastFilterMacs * sizeof(RTMAC)); 1318 1319 if (pThis->cUnicastFilterMacs < VIRTIONET_MAC_FILTER_LEN) 1320 memset(&pThis->aMacUnicastFilter[pThis->cUnicastFilterMacs], 0, 1321 (VIRTIONET_MAC_FILTER_LEN - pThis->cUnicastFilterMacs) * sizeof(RTMAC)); 1322 1323 rc = pHlp->pfnSSMGetMem(pSSM, pThis->aVlanFilter, sizeof(pThis->aVlanFilter)); 1324 AssertRCReturn(rc, rc); 1103 1325 /* 1104 1326 * Call the virtio core to let it load its state. 1105 1327 */ 1106 rc = virtioCoreR3LoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM); 1107 1328 rc = virtioCoreR3ModernDeviceLoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, uVersion, 1329 VIRTIONET_SAVEDSTATE_VERSION, pThis->cVirtqs); 1330 AssertRCReturn(rc, rc); 1331 /* 1332 * Since the control queue is created proactively in the constructor to accomodate worst-case 1333 * legacy guests, even though the queue may have been deducted from queue count while saving state, 1334 * we must explicitly remove queue and associated worker thread and context at this point, 1335 * or presence of bogus control queue will confuse operations. 1336 */ 1337 PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[CTRLQIDX]; 1338 if (FEATURE_DISABLED(CTRL_VQ) || !virtioCoreIsVirtqEnabled(&pThis->Virtio, CTRLQIDX)) 1339 { 1340 virtioCoreR3VirtqDetach(&pThis->Virtio, CTRLQIDX); 1341 virtioNetR3VirtqDestroy(&pThis->Virtio, pVirtq); 1342 pVirtq->fAttachedToVirtioCore = false; 1343 --pThis->cWorkers; 1344 } 1108 1345 /* 1109 1346 * Nudge queue workers 1110 1347 */ 1111 for (int uIdxWorker = 0; uIdxWorker < pThis->cWorkers; uIdxWorker++) 1112 { 1113 PVIRTIONETWORKER pWorker = &pThis->aWorkers[uIdxWorker]; 1114 PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uIdxWorker]; 1348 for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) 1349 { 1350 pVirtq = &pThis->aVirtqs[uVirtqNbr]; 1115 1351 if (pVirtq->fAttachedToVirtioCore) 1116 1352 { 1117 Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName)); 1118 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 1119 AssertRCReturn(rc, rc); 1353 if (pVirtq->fHasWorker) 1354 { 1355 PVIRTIONETWORKER pWorker = &pThis->aWorkers[uVirtqNbr]; 1356 Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName)); 1357 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 1358 AssertRCReturn(rc, rc); 1359 } 1120 1360 } 1121 1361 } 1362 pThis->virtioNetConfig.uStatus = pThis->Virtio.fDeviceStatus; /* reflects state to guest driver */ 1363 pThis->fVirtioReady = pThis->Virtio.fDeviceStatus & VIRTIO_STATUS_DRIVER_OK; 1364 1122 1365 return rc; 1123 1366 } … … 1126 1369 * @callback_method_impl{FNSSMDEVSAVEEXEC} 1127 1370 */ 1128 static DECLCALLBACK(int) virtioNetR3 SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)1371 static DECLCALLBACK(int) virtioNetR3ModernSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) 1129 1372 { 1130 1373 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); … … 1135 1378 Log7Func(("[%s] SAVE EXEC!!\n", pThis->szInst)); 1136 1379 1380 /* Store a dummy MAC address that would never be actually assigned to a NIC 1381 * so that when load exec handler is called it can be easily determined 1382 * whether saved state is modern or legacy. This works because original 1383 * legacy code stored assigned NIC address as the first item of SSM state 1384 */ 1385 RTMAC uVersionMarkerMac = VIRTIONET_VERSION_MARKER_MAC_ADDR; 1386 pHlp->pfnSSMPutMem(pSSM, &uVersionMarkerMac.au8, sizeof(uVersionMarkerMac.au8)); 1387 1137 1388 pHlp->pfnSSMPutU64( pSSM, pThis->fNegotiatedFeatures); 1138 1389 … … 1142 1393 for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) 1143 1394 pHlp->pfnSSMPutBool(pSSM, pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore); 1144 1145 /* Save config area */ 1146 #if FEATURE_OFFERED(STATUS) 1395 /* 1396 1397 * Save device config area (accessed via MMIO) 1398 */ 1147 1399 pHlp->pfnSSMPutMem( pSSM, pThis->virtioNetConfig.uMacAddress.au8, 1148 1400 sizeof(pThis->virtioNetConfig.uMacAddress.au8)); 1401 #if FEATURE_OFFERED(STATUS) 1402 pHlp->pfnSSMPutU16( pSSM, pThis->virtioNetConfig.uStatus); 1403 #else 1404 /* 1405 * Relevant values are lower bits. Forcing this to 0xffff let's loadExec know this 1406 * feature was not enabled in saved state. VirtIO 1.0, 5.1.4 1407 */ 1408 pHlp->pfnSSMPutU16( pSSM, 0xffff); 1409 1149 1410 #endif 1150 1411 #if FEATURE_OFFERED(MQ) 1151 1412 pHlp->pfnSSMPutU16( pSSM, pThis->virtioNetConfig.uMaxVirtqPairs); 1413 #else 1414 /* 1415 * Legal values for max_virtqueue_pairs are 0x1 -> 0x8000 *. Forcing zero let's loadExec know this 1416 * feature was not enabled in saved state. VirtIO 1.0, 5.1.4.1 1417 */ 1418 pHlp->pfnSSMPutU16( pSSM, 0); 1152 1419 #endif 1153 1420 … … 1173 1440 * Call the virtio core to let it save its state. 1174 1441 */ 1175 return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM );1442 return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, VIRTIONET_SAVEDSTATE_VERSION, pThis->cVirtqs); 1176 1443 } 1177 1444 … … 1183 1450 #ifdef IN_RING3 1184 1451 1185 DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb) 1186 { 1452 /** 1453 * Perform 16-bit 1's compliment checksum on provided packet in accordance with VirtIO specification, 1454 * pertinent to VIRTIO_NET_F_CSUM feature, which 'offloads' the Checksum feature from the driver 1455 * to save processor cycles, which is ironic in our case, where the controller device ('network card') 1456 * is emulated on the virtualization host. 1457 * 1458 * @note See VirtIO 1.0 spec, 5.1.6.2 Packet Transmission 1459 * 1460 * @param pBuf Pointer to r/w buffer with any portion to calculate checksum for 1461 * @param cbSize Number of bytes to checksum 1462 * @param uStart Where to start the checksum within the buffer 1463 * @param uOffset Offset past uStart point in the buffer to store checksum result 1464 * 1465 */ 1466 DECLINLINE(void) virtioNetR3Calc16BitChecksum(uint8_t *pBuf, size_t cb, uint16_t uStart, uint16_t uOffset) 1467 { 1468 AssertReturnVoid(uStart < cb); 1469 AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cb); 1470 1187 1471 uint32_t chksum = 0; 1188 uint16_t *pu = (uint16_t *)pvBuf; 1189 1472 uint16_t *pu = (uint16_t *)(pBuf + uStart); 1473 1474 cb -= uStart; 1190 1475 while (cb > 1) 1191 1476 { … … 1194 1479 } 1195 1480 if (cb) 1196 chksum += *(uint8_t *)pu;1481 chksum += *(uint8_t *)pu; 1197 1482 while (chksum >> 16) 1198 1483 chksum = (chksum >> 16) + (chksum & 0xFFFF); 1199 return ~chksum; 1200 } 1201 1202 DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset) 1203 { 1204 AssertReturnVoid(uStart < cbSize); 1205 AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize); 1206 *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Checkum16(pBuf + uStart, cbSize - uStart); 1484 1485 /* Store 1's compliment of calculated sum */ 1486 *(uint16_t *)(pBuf + uStart + uOffset) = ~chksum; 1207 1487 } 1208 1488 … … 1237 1517 } 1238 1518 1239 /* 1240 * Returns true if VirtIO core and device are in a running and operational state 1519 /** 1520 * Check that the core is setup and ready and co-configured with guest virtio driver, 1521 * and verifies that the VM is running. 1522 * 1523 * @returns true if VirtIO core and device are in a running and operational state 1241 1524 */ 1242 1525 DECLINLINE(bool) virtioNetIsOperational(PVIRTIONET pThis, PPDMDEVINS pDevIns) … … 1265 1548 { 1266 1549 int rc = VERR_INVALID_STATE; 1267 1550 Log8Func(("[%s] ", pThis->szInst)); 1268 1551 if (!virtioNetIsOperational(pThis, pDevIns)) 1269 Log8 Func(("[%s]No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));1270 1271 else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq->uIdx))1272 Log8 Func(("[%s] No Rx bufs available. (%s not enabled)\n", pThis->szInst,pRxVirtq->szName));1273 1274 else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq->uIdx))1275 Log8 Func(("[%s] No Rx bufs available. (%s empty)\n", pThis->szInst,pRxVirtq->szName));1552 Log8(("No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst)); 1553 1554 else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq->uIdx)) 1555 Log8(("[No Rx bufs available. (%s not enabled)\n", pRxVirtq->szName)); 1556 1557 else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq->uIdx)) 1558 Log8(("No Rx bufs available. (%s empty)\n", pRxVirtq->szName)); 1276 1559 1277 1560 else 1278 1561 { 1279 Log8Func(("[%s] %s has empty guest bufs avail\n", pThis->szInst, pRxVirtq->szName)); 1562 Log8(("%s has %d empty guest bufs in avail ring\n", pRxVirtq->szName, 1563 virtioCoreVirtqAvailBufCount(pDevIns, &pThis->Virtio, pRxVirtq->uIdx))); 1280 1564 rc = VINF_SUCCESS; 1281 1565 } … … 1284 1568 } 1285 1569 1286 static bool virtioNetR3RxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETVIRTQ *pRxVirtq) 1570 /** 1571 * Find an Rx queue that has Rx packets in it, if *any* do. 1572 * 1573 * @todo When multiqueue (MQ) mode is fully supported and tested, some kind of round-robin 1574 * or randomization scheme should probably be incorporated here. 1575 * 1576 * @returns true if Rx pkts avail on queue and sets pRxVirtq to point to queue w/pkts found 1577 * @thread RX 1578 * 1579 */ 1580 static bool virtioNetR3AreRxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETVIRTQ *pRxVirtq) 1287 1581 { 1288 1582 for (int uVirtqPair = 0; uVirtqPair < pThis->cVirtqPairs; uVirtqPair++) … … 1311 1605 return VERR_INTERRUPTED; 1312 1606 1313 if (virtioNetR3 RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))1314 { 1315 Log10Func(("[%s] Rx bufs nowavailable, releasing waiter...\n", pThis->szInst));1607 if (virtioNetR3AreRxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */)) 1608 { 1609 Log10Func(("[%s] Rx bufs available, releasing waiter...\n", pThis->szInst)); 1316 1610 return VINF_SUCCESS; 1317 1611 } … … 1321 1615 LogFunc(("[%s] %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : "")); 1322 1616 1323 1324 1617 ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, true); 1325 1618 STAM_PROFILE_START(&pThis->StatRxOverflow, a); 1326 1619 1327 1620 do { 1328 if (virtioNetR3 RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))1621 if (virtioNetR3AreRxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */)) 1329 1622 { 1330 1623 Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst)); … … 1357 1650 return VERR_INTERRUPTED; 1358 1651 } 1359 1360 1652 1361 1653 /** … … 1438 1730 return (*(char*)pvBuf) & 1; 1439 1731 } 1732 1440 1733 /** 1441 1734 * Determines if the packet is to be delivered to upper layer. … … 1449 1742 { 1450 1743 1744 #ifdef LOG_ENABLED 1451 1745 if (LogIs11Enabled()) 1452 1746 { … … 1465 1759 pvBuf, pszType)); 1466 1760 } 1761 #endif 1467 1762 1468 1763 if (pThis->fPromiscuous) { … … 1485 1780 { 1486 1781 Log11(("acpt (bcast)\n")); 1782 #ifdef LOG_ENABLED 1487 1783 if (LogIs12Enabled()) 1488 1784 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1785 #endif 1489 1786 return true; 1490 1787 } … … 1492 1789 { 1493 1790 Log11(("acpt (all-mcast)\n")); 1791 #ifdef LOG_ENABLED 1494 1792 if (LogIs12Enabled()) 1495 1793 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1794 #endif 1496 1795 return true; 1497 1796 } … … 1500 1799 { 1501 1800 Log11(("acpt (to-node)\n")); 1801 #ifdef LOG_ENABLED 1502 1802 if (LogIs12Enabled()) 1503 1803 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1804 #endif 1504 1805 return true; 1505 1806 } … … 1510 1811 { 1511 1812 Log11(("acpt (mcast whitelist)\n")); 1813 #ifdef LOG_ENABLED 1512 1814 if (LogIs12Enabled()) 1513 1815 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming"); 1816 #endif 1514 1817 return true; 1515 1818 } … … 1522 1825 return true; 1523 1826 } 1524 1827 #ifdef LOG_ENABLED 1525 1828 if (LogIs11Enabled()) 1526 1829 Log(("... reject\n")); 1830 #endif 1527 1831 1528 1832 return false; 1529 1833 } 1530 1834 1531 static int virtioNetR3CopyRxPktToGuest(PPDMDEVINS pDevIns, PVIRTIONET pThis, const void *pvBuf, size_t cb, 1532 PVIRTIONETPKTHDR rxPktHdr, uint16_t cSegsAllocated, 1533 PRTSGBUF pVirtSegBufToGuest, PRTSGSEG paVirtSegsToGuest, 1534 PVIRTIONETVIRTQ pRxVirtq) 1535 { 1536 RTGCPHYS GCPhysPktHdrNumBuffers = 0; 1537 uint8_t fAddPktHdr = true; 1538 uint16_t cVirtqBufs = 0; 1539 uint64_t uOffset = 0; 1540 1541 while (uOffset < cb) 1542 { 1543 PVIRTQBUF pVirtqBuf = NULL; 1544 1545 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true); 1546 AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc); 1547 1548 /** @todo Find a better way to deal with this */ 1549 AssertMsgReturnStmt(rc == VINF_SUCCESS && pVirtqBuf->cbPhysReturn, 1550 ("Not enough Rx buffers in queue to accomodate ethernet packet\n"), 1551 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf), 1552 VERR_INTERNAL_ERROR); 1553 1554 /* Length of first seg of guest Rx S/G buf should never be less than sthe packet header. 1555 * Otherwise code has to become more complicated, e.g. locate & cache seg idx & offset of 1556 * virtio_net_header.num_buffers, to facilitate deferring updating GCPhys memory. 1557 * Re-visit if needed */ 1558 1559 AssertMsgReturn(pVirtqBuf->pSgPhysReturn->paSegs[0].cbSeg >= pThis->cbPktHdr, 1560 ("Out of Memory"), VERR_NO_MEMORY); 1561 1562 size_t cbBufRemaining = pVirtqBuf->cbPhysReturn; 1563 1564 1565 /* Fill the Guest Rx buffer with data received from the interface */ 1566 for (uint16_t cSegs = 0; uOffset < cb && cbBufRemaining; ) 1835 1836 /** 1837 * This handles the case where Rx packet must be transfered to guest driver via multiple buffers using 1838 * copy tactics slower than preferred method using a single virtq buf. Yet this is an available option 1839 * for guests. Although cited in the spec it's to accomodate guest that perhaps have memory constraints 1840 * wherein guest may benefit from smaller buffers (see MRG_RXBUF feature), in practice it is seen 1841 * that without MRG_RXBUF the linux guest enqueues 'huge' multi-segment buffers so that the largest 1842 * conceivable Rx packet can be contained in a single buffer, where for most transactions most of that 1843 * memory will be unfilled, so it is typically both wasteful and *slower* to avoid MRG_RXBUF. 1844 * 1845 * As an optimization, this multi-buffer copy is only used when: 1846 * 1847 * A. Guest has negotiated MRG_RXBUF 1848 * B. Next packet in the Rx avail queue isn't big enough to contain Rx pkt hdr+data. 1849 * 1850 * Architecture is defined in VirtIO 1.1 5.1.6 (Device Operations), which has improved 1851 * wording over the VirtIO 1.0 specification, but, as an implementation note, there is one 1852 * ambiguity that needs clarification: 1853 * 1854 * The VirtIO 1.1, 5.1.6.4 explains something in a potentially misleading way. And note, 1855 * the VirtIO spec makes a document-wide assertion that the distinction between 1856 * "SHOULD" and "MUST" is to be taken quite literally. 1857 * 1858 * The confusion is that VirtIO 1.1, 5.1.6.3.1 essentially says guest driver "SHOULD" populate 1859 * Rx queue with buffers large enough to accomodate full pkt hdr + data. That's a grammatical 1860 * error (dangling participle). 1861 * 1862 * In practice we MUST assume "SHOULD" strictly applies to the word *populate*, -not- to buffer 1863 * size, because ultimately buffer minimum size is predicated on configuration parameters, 1864 * specifically, when MRG_RXBUF feature is disabled, the driver *MUST* provide Rx bufs 1865 * (if and when it can provide them), that are *large enough* to hold pkt hdr + payload. 1866 * 1867 * Therefore, proper interpretation of 5.1.6.3.1 is, the guest *should* (ideally) keep Rx virtq 1868 * populated with appropriately sized buffers to *prevent starvation* (i.e. starvation may be 1869 * unavoidable thus can't be prohibited). As it would be a ludicrous to presume 5.1.6.3.1 is 1870 * giving guests leeway to violate MRG_RXBUF feature buf size constraints. 1871 * 1872 * @param pDevIns PDM instance 1873 * @param pThis Device instance 1874 * @param pvBuf Pointer to incoming GSO Rx data from downstream device 1875 * @param cb Amount of data given 1876 * @param rxPktHdr Rx pkt Header that's been massaged into VirtIO semantics 1877 * @param pRxVirtq Pointer to Rx virtq 1878 * @param pVirtqBuf Initial virtq buffer to start copying Rx hdr/pkt to guest into 1879 * 1880 */ 1881 static int virtioNetR3RxPktMultibufXfer(PPDMDEVINS pDevIns, PVIRTIONET pThis, uint8_t *pvPktBuf, size_t cb, 1882 PVIRTIONETPKTHDR pRxPktHdr, PVIRTIONETVIRTQ pRxVirtq, PVIRTQBUF pVirtqBuf) 1883 { 1884 1885 size_t cbBufRemaining = pVirtqBuf->cbPhysReturn; 1886 size_t cbPktHdr = pThis->cbPktHdr; 1887 1888 AssertMsgReturn(cbBufRemaining >= pThis->cbPktHdr, 1889 ("guest-provided Rx buf not large enough to store pkt hdr"), VERR_INTERNAL_ERROR); 1890 1891 Log7Func((" Sending packet header to guest...\n")); 1892 1893 /* Copy packet header to rx buf provided by caller. */ 1894 uint32_t cbHdrEnqueued = pVirtqBuf->cbPhysReturn == cbPktHdr ? cbPktHdr : 0; 1895 virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cbPktHdr, pRxPktHdr, pVirtqBuf, cbHdrEnqueued); 1896 1897 /* Cache address of uNumBuffers field of pkthdr to update ex post facto */ 1898 RTGCPHYS GCPhysNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers); 1899 uint16_t cVirtqBufsUsed = 1; 1900 cbBufRemaining -= cbPktHdr; 1901 /* 1902 * Copy packet to guest using as many buffers as necessary, tracking and handling whether 1903 * the buf containing the packet header was already written to the Rx queue's used buffer ring. 1904 */ 1905 uint64_t uPktOffset = 0; 1906 while(uPktOffset < cb) 1907 { 1908 Log7Func((" Sending packet data (in buffer #%d) to guest...\n", cVirtqBufsUsed)); 1909 size_t cbBounded = RT_MIN(cbBufRemaining, cb - uPktOffset); 1910 (void) virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cbBounded, 1911 pvPktBuf + uPktOffset, pVirtqBuf, cbBounded + (cbPktHdr - cbHdrEnqueued) /* cbEnqueue */); 1912 ++cVirtqBufsUsed; 1913 cbBufRemaining -= cbBounded; 1914 uPktOffset -= cbBounded; 1915 if (uPktOffset < cb) 1567 1916 { 1568 if (fAddPktHdr) 1569 { 1570 /* Lead with packet header */ 1571 paVirtSegsToGuest[0].cbSeg = pThis->cbPktHdr; 1572 paVirtSegsToGuest[0].pvSeg = RTMemAlloc(pThis->cbPktHdr); 1573 AssertReturn(paVirtSegsToGuest[0].pvSeg, VERR_NO_MEMORY); 1574 cbBufRemaining -= pThis->cbPktHdr; 1575 1576 memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, pThis->cbPktHdr); 1577 1578 if (pThis->ePktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx) 1579 { 1580 /* Calculate & cache GCPhys addr of field to update after final value is known */ 1581 GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys 1582 + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers); 1583 } 1584 fAddPktHdr = false; 1585 cSegs++; 1586 } 1587 1588 if (cSegs >= cSegsAllocated) 1589 { 1590 cSegsAllocated <<= 1; /* double allocation size */ 1591 paVirtSegsToGuest = (PRTSGSEG)RTMemRealloc(paVirtSegsToGuest, sizeof(RTSGSEG) * cSegsAllocated); 1592 if (!paVirtSegsToGuest) 1593 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf); 1594 AssertReturn(paVirtSegsToGuest, VERR_NO_MEMORY); 1595 } 1596 1597 /* Append remaining Rx pkt or as much current desc chain has room for */ 1598 size_t cbLimited = RT_MIN(cb, cbBufRemaining); 1599 paVirtSegsToGuest[cSegs].cbSeg = cbLimited; 1600 paVirtSegsToGuest[cSegs].pvSeg = ((uint8_t *)pvBuf) + uOffset; 1601 cbBufRemaining -= cbLimited; 1602 uOffset += cbLimited; 1603 cVirtqBufs++; 1604 cSegs++; 1605 RTSgBufInit(pVirtSegBufToGuest, paVirtSegsToGuest, cSegs); 1606 Log7Func(("Send Rx pkt to guest...\n")); 1607 STAM_PROFILE_START(&pThis->StatReceiveStore, a); 1608 virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, 1609 pVirtSegBufToGuest, pVirtqBuf, true /* fFence */); 1610 STAM_PROFILE_STOP(&pThis->StatReceiveStore, a); 1611 1612 if (FEATURE_DISABLED(MRG_RXBUF)) 1613 break; 1917 cbHdrEnqueued = cbPktHdr; 1918 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true); 1919 1920 AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc); 1921 1922 AssertMsgReturnStmt(rc == VINF_SUCCESS && pVirtqBuf->cbPhysReturn, 1923 ("Not enough Rx buffers in queue to accomodate ethernet packet\n"), 1924 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf), 1925 VERR_INTERNAL_ERROR); 1614 1926 } 1615 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf); 1616 } 1617 1618 if (uOffset < cb) 1619 { 1620 LogFunc(("[%s] Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb)); 1621 return VERR_TOO_MUCH_DATA; 1622 } 1623 1624 1625 if (pThis->ePktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx) 1626 { 1627 /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */ 1628 int rc = virtioCoreGCPhysWrite(&pThis->Virtio, pDevIns, GCPhysPktHdrNumBuffers, &cVirtqBufs, sizeof(cVirtqBufs)); 1629 AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc); 1630 } 1631 1927 } 1928 1929 /* Fix-up pkthdr (in guest phys. memory) with number of buffers (descriptors) that were processed */ 1930 int rc = virtioCoreGCPhysWrite(&pThis->Virtio, pDevIns, GCPhysNumBuffers, &cVirtqBufsUsed, sizeof(cVirtqBufsUsed)); 1931 AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc); 1932 1933 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf); 1632 1934 virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx); 1633 1634 return VINF_SUCCESS; 1635 } 1636 1935 Log7(("\n")); 1936 return rc; 1937 } 1637 1938 1638 1939 /** … … 1651 1952 * @thread RX 1652 1953 */ 1653 static int virtioNetR3HandleRxPacket(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1654 const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso, PVIRTIONETVIRTQ pRxVirtq) 1954 1955 static int virtioNetR3CopyRxPktToGuest(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, const void *pvBuf, size_t cb, 1956 PVIRTIONETPKTHDR pRxPktHdr, uint8_t cbPktHdr, PVIRTIONETVIRTQ pRxVirtq) 1655 1957 { 1656 1958 RT_NOREF(pThisCC); 1657 1658 LogFunc(("[%s] (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present")); 1659 VIRTIONETPKTHDR rxPktHdr; 1660 1959 PVIRTQBUF pVirtqBuf; 1960 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true); 1961 1962 AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc); 1963 1964 AssertMsgReturnStmt(rc == VINF_SUCCESS && pVirtqBuf->cbPhysReturn, 1965 ("Not enough Rx buffers or capacity to accommodate ethernet packet\n"), 1966 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf), 1967 VERR_INTERNAL_ERROR); 1968 /* 1969 * Try to do fast (e.g. single-buffer) copy to guest, even if MRG_RXBUF feature is enabled 1970 * If 1971 */ 1972 STAM_PROFILE_START(&pThis->StatReceiveStore, a); 1973 if (RT_LIKELY(FEATURE_DISABLED(MRG_RXBUF)) 1974 || RT_LIKELY(pVirtqBuf->cbPhysReturn > cb + cbPktHdr)) 1975 { 1976 Log7Func(("Send Rx packet header and data to guest (single-buffer copy)...\n")); 1977 pRxPktHdr->uNumBuffers = 1; 1978 rc = virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cbPktHdr, pRxPktHdr, pVirtqBuf, 0 /* cbEnqueue */); 1979 AssertMsgReturn(rc == VINF_SUCCESS, ("%Rrc\n", rc), rc); 1980 rc = virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cb, pvBuf, pVirtqBuf, cbPktHdr + cb /* cbEnqueue */); 1981 AssertMsgReturn(rc == VINF_SUCCESS, ("%Rrc\n", rc), rc); 1982 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf); 1983 virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx); 1984 } 1985 else 1986 { 1987 Log7Func(("Send Rx pkt to guest (merged-buffer copy [MRG_RXBUF feature])...\n")); 1988 rc = virtioNetR3RxPktMultibufXfer(pDevIns, pThis, (uint8_t *)pvBuf, cb, pRxPktHdr, pRxVirtq, pVirtqBuf); 1989 return rc; 1990 } 1991 STAM_PROFILE_STOP(&pThis->StatReceiveStore, a); 1992 return VINF_SUCCESS; 1993 } 1994 1995 /** 1996 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso} 1997 */ 1998 static DECLCALLBACK(int) virtioNetR3NetworkDown_ReceiveGso( 1999 PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso) 2000 { 2001 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 2002 PPDMDEVINS pDevIns = pThisCC->pDevIns; 2003 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2004 VIRTIONETPKTHDR rxPktHdr = { 0, VIRTIONET_HDR_GSO_NONE, 0, 0, 0, 0, 0 }; 2005 2006 if (!pThis->fVirtioReady) 2007 { 2008 LogRelFunc(("VirtIO not ready, aborting downstream receive\n")); 2009 return VERR_INTERRUPTED; 2010 } 2011 /* 2012 * If GSO (Global Segment Offloading) was received from downstream PDM network device, massage the 2013 * PDM-provided GSO parameters into VirtIO semantics, which get passed to guest virtio-net via 2014 * Rx pkt header. See VirtIO 1.1, 5.1.6 Device Operation for more information. 2015 */ 1661 2016 if (pGso) 1662 2017 { 1663 Log2Func(("[%s] gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n", 1664 pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal, 1665 pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 1666 1667 rxPktHdr.uFlags = VIRTIONET_HDR_F_NEEDS_CSUM; 2018 LogFunc(("[%s] (%RTmac) \n", pThis->szInst, pvBuf)); 2019 2020 rxPktHdr.uFlags = VIRTIONET_HDR_F_NEEDS_CSUM; 2021 rxPktHdr.uHdrLen = pGso->cbHdrsTotal; 2022 rxPktHdr.uGsoSize = pGso->cbMaxSeg; 2023 rxPktHdr.uChksumStart = pGso->offHdr2; 2024 1668 2025 switch (pGso->u8Type) 1669 2026 { … … 1681 2038 break; 1682 2039 default: 1683 return VERR_INVALID_PARAMETER; 2040 LogFunc(("[%s] GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type)); 2041 return VERR_NOT_SUPPORTED; 1684 2042 } 1685 rxPktHdr.uHdrLen = pGso->cbHdrsTotal;1686 rxPktHdr.uGsoSize = pGso->cbMaxSeg;1687 rxPktHdr.uChksumStart = pGso->offHdr2;1688 rxPktHdr.uNumBuffers = 0;1689 2043 STAM_REL_COUNTER_INC(&pThis->StatReceiveGSO); 1690 } 1691 else 1692 { 1693 rxPktHdr.uFlags = 0; 1694 rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_NONE; 1695 rxPktHdr.uHdrLen = 0; 1696 rxPktHdr.uGsoSize = 0; 1697 rxPktHdr.uChksumStart = 0; 1698 rxPktHdr.uChksumOffset = 0; 1699 rxPktHdr.uNumBuffers = 0; 1700 } 1701 1702 uint16_t cSegsAllocated = VIRTIONET_RX_SEG_COUNT; 1703 1704 PRTSGBUF pVirtSegBufToGuest = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF)); 1705 AssertReturn(pVirtSegBufToGuest, VERR_NO_MEMORY); 1706 1707 PRTSGSEG paVirtSegsToGuest = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * cSegsAllocated); 1708 AssertReturnStmt(paVirtSegsToGuest, RTMemFree(pVirtSegBufToGuest), VERR_NO_MEMORY); 1709 1710 int rc = virtioNetR3CopyRxPktToGuest(pDevIns, pThis, pvBuf, cb, &rxPktHdr, cSegsAllocated, 1711 pVirtSegBufToGuest, paVirtSegsToGuest, pRxVirtq); 1712 1713 RTMemFree(paVirtSegsToGuest); 1714 RTMemFree(pVirtSegBufToGuest); 1715 1716 Log7(("\n")); 1717 return rc; 1718 } 1719 1720 /** 1721 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso} 1722 */ 1723 static DECLCALLBACK(int) virtioNetR3NetworkDown_ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf, 1724 size_t cb, PCPDMNETWORKGSO pGso) 1725 { 1726 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 1727 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1728 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1729 1730 if (!pThis->fVirtioReady) 1731 { 1732 LogRelFunc(("VirtIO not ready, aborting downstream receive\n")); 1733 return VERR_INTERRUPTED; 1734 } 1735 1736 if (pGso) 1737 { 1738 uint32_t uFeatures = pThis->fNegotiatedFeatures; 1739 1740 switch (pGso->u8Type) 1741 { 1742 case PDMNETWORKGSOTYPE_IPV4_TCP: 1743 uFeatures &= VIRTIONET_F_GUEST_TSO4; 1744 break; 1745 case PDMNETWORKGSOTYPE_IPV6_TCP: 1746 uFeatures &= VIRTIONET_F_GUEST_TSO6; 1747 break; 1748 case PDMNETWORKGSOTYPE_IPV4_UDP: 1749 case PDMNETWORKGSOTYPE_IPV6_UDP: 1750 uFeatures &= VIRTIONET_F_GUEST_UFO; 1751 break; 1752 default: 1753 uFeatures = 0; 1754 break; 1755 } 1756 if (!uFeatures) 1757 { 1758 LogFunc(("[%s] GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type)); 1759 return VERR_NOT_SUPPORTED; 1760 } 1761 } 1762 1763 Log10Func(("[%s] pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso)); 1764 1765 /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue 1766 selection algorithm feasible or even necessary to prevent starvation? */ 1767 2044 Log2Func(("[%s] gso type=%#x, cbHdrsTotal=%u cbHdrsSeg=%u mss=%u offHdr1=%#x offHdr2=%#x\n", 2045 pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg, 2046 pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 2047 } 2048 2049 /* 2050 * Find a virtq with Rx bufs on avail ring, if any, and copy the packet to the guest's Rx buffer. 2051 * @todo pk: PROBABLY NOT A SOPHISTICATED ENOUGH QUEUE SELECTION ALGORTITH FOR OPTIMAL MQ (FEATURE) SUPPORT 2052 */ 1768 2053 for (int uVirtqPair = 0; uVirtqPair < pThis->cVirtqPairs; uVirtqPair++) 1769 2054 { 1770 1771 2055 PVIRTIONETVIRTQ pRxVirtq = &pThis->aVirtqs[RXQIDX(uVirtqPair)]; 1772 2056 if (RT_SUCCESS(virtioNetR3CheckRxBufsAvail(pDevIns, pThis, pRxVirtq))) 1773 2057 { 2058 int rc = VINF_SUCCESS; 1774 2059 STAM_PROFILE_START(&pThis->StatReceive, a); 1775 2060 virtioNetR3SetReadLed(pThisCC, true); 1776 1777 int rc = VINF_SUCCESS;1778 2061 if (virtioNetR3AddressFilter(pThis, pvBuf, cb)) 1779 2062 { 1780 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso, pRxVirtq); 2063 /* rxPktHdr is local stack variable that should not go out of scope in this use */ 2064 rc = virtioNetR3CopyRxPktToGuest(pDevIns, pThis, pThisCC, pvBuf, cb, &rxPktHdr, pThis->cbPktHdr, pRxVirtq); 1781 2065 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb); 1782 2066 } 1783 1784 2067 virtioNetR3SetReadLed(pThisCC, false); 1785 2068 STAM_PROFILE_STOP(&pThis->StatReceive, a); … … 1795 2078 static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb) 1796 2079 { 2080 2081 #ifdef LOG_ENABLED 2082 PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown); 2083 PPDMDEVINS pDevIns = pThisCC->pDevIns; 2084 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2085 LogFunc(("[%s] (%RTmac)\n", pThis->szInst, pvBuf)); 2086 #endif 2087 1797 2088 return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL); 1798 2089 } 1799 2090 1800 2091 /* 2092 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's Rx packet receive filtering. 2093 * See VirtIO 1.0, 5.1.6.5.1 2094 * 2095 * @param pThis virtio-net instance 2096 * @param pCtrlPktHdr Control packet header (which includes command parameters) 2097 * @param pVirtqBuf Buffer from ctrlq buffer (contains command data) 2098 */ 1801 2099 static uint8_t virtioNetR3CtrlRx(PVIRTIONET pThis, PVIRTIONETCC pThisCC, 1802 2100 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf) … … 1864 2162 } 1865 2163 2164 /* 2165 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's MAC filter tables 2166 * See VirtIO 1.0, 5.1.6.5.2 2167 * 2168 * @param pThis virtio-net instance 2169 * @param pCtrlPktHdr Control packet header (which includes command parameters) 2170 * @param pVirtqBuf Buffer from ctrlq buffer (contains command data) 2171 */ 1866 2172 static uint8_t virtioNetR3CtrlMac(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf) 1867 2173 { … … 1882 2188 ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd\n"), VIRTIONET_ERROR); 1883 2189 1884 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->rxFilterMacDefault, sizeof( VIRTIONET_CTRL_MAC_TABLE_LEN));2190 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->rxFilterMacDefault, sizeof(RTMAC)); 1885 2191 break; 1886 2192 } … … 1890 2196 1891 2197 /* Load unicast MAC filter table */ 1892 1893 2198 AssertMsgReturn(cbRemaining >= sizeof(cMacs), 1894 2199 ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd\n"), VIRTIONET_ERROR); … … 1896 2201 /* Fetch count of unicast filter MACs from guest buffer */ 1897 2202 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &cMacs, sizeof(cMacs)); 1898 1899 2203 cbRemaining -= sizeof(cMacs); 1900 2204 … … 1905 2209 uint32_t cbMacs = cMacs * sizeof(RTMAC); 1906 2210 2211 AssertMsgReturn(cbMacs <= sizeof(pThis->aMacUnicastFilter) / sizeof(RTMAC), 2212 ("Guest provided Unicast MAC filter table exceeds hardcoded table size"), VIRTIONET_ERROR); 2213 1907 2214 AssertMsgReturn(cbRemaining >= cbMacs, 1908 2215 ("Virtq buffer too small to process CTRL_MAC_TABLE_SET cmd\n"), VIRTIONET_ERROR); 1909 2216 2217 1910 2218 /* Fetch unicast table contents from guest buffer */ 1911 2219 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->aMacUnicastFilter, cbMacs); 1912 1913 2220 cbRemaining -= cbMacs; 1914 2221 } … … 1921 2228 /* Fetch count of multicast filter MACs from guest buffer */ 1922 2229 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &cMacs, sizeof(cMacs)); 1923 1924 2230 cbRemaining -= sizeof(cMacs); 1925 2231 1926 2232 Log10Func(("[%s] Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs)); 1927 1928 2233 1929 2234 if (cMacs) … … 1931 2236 uint32_t cbMacs = cMacs * sizeof(RTMAC); 1932 2237 2238 AssertMsgReturn(cbMacs <= sizeof(pThis->aMacMulticastFilter) / sizeof(RTMAC), 2239 ("Guest provided Unicast MAC filter table exceeds hardcoded table size"), VIRTIONET_ERROR); 2240 1933 2241 AssertMsgReturn(cbRemaining >= cbMacs, 1934 2242 ("Virtq buffer too small to process CTRL_MAC_TABLE_SET cmd\n"), VIRTIONET_ERROR); … … 1936 2244 /* Fetch multicast table contents from guest buffer */ 1937 2245 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->aMacMulticastFilter, cbMacs); 1938 1939 2246 cbRemaining -= cbMacs; 1940 2247 } … … 1943 2250 #ifdef LOG_ENABLED 1944 2251 LogFunc(("[%s] unicast MACs:\n", pThis->szInst)); 1945 for(unsigned i = 0; i < cMacs; i++)2252 for(unsigned i = 0; i < pThis->cUnicastFilterMacs; i++) 1946 2253 LogFunc((" %RTmac\n", &pThis->aMacUnicastFilter[i])); 1947 2254 1948 2255 LogFunc(("[%s] multicast MACs:\n", pThis->szInst)); 1949 for(unsigned i = 0; i < cMacs; i++)2256 for(unsigned i = 0; i < pThis->cMulticastFilterMacs; i++) 1950 2257 LogFunc((" %RTmac\n", &pThis->aMacMulticastFilter[i])); 1951 2258 #endif … … 1959 2266 } 1960 2267 2268 /* 2269 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's MQ (multiqueue) operations. 2270 * See VirtIO 1.0, 5.1.6.5.5 2271 * 2272 * @param pThis virtio-net instance 2273 * @param pCtrlPktHdr Control packet header (which includes command parameters) 2274 * @param pVirtqBuf Buffer from ctrlq buffer (contains command data) 2275 */ 1961 2276 static uint8_t virtioNetR3CtrlMultiQueue(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMDEVINS pDevIns, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf) 1962 2277 { … … 1996 2311 if (pThis->cVirtqPairs > pThis->cInitializedVirtqPairs) 1997 2312 { 1998 virtioNetR3SetVirtqNames(pThis );2313 virtioNetR3SetVirtqNames(pThis, virtioCoreIsLegacyMode(&pThis->Virtio)); 1999 2314 int rc = virtioNetR3CreateWorkerThreads(pDevIns, pThis, pThisCC); 2000 2315 if (RT_FAILURE(rc)) … … 2007 2322 } 2008 2323 2324 /* 2325 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's VLAN filtering. 2326 * See VirtIO 1.0, 5.1.6.5.3 2327 * 2328 * @param pThis virtio-net instance 2329 * @param pCtrlPktHdr Control packet header (which includes command parameters) 2330 * @param pVirtqBuf Buffer from ctrlq buffer (contains command data) 2331 */ 2009 2332 static uint8_t virtioNetR3CtrlVlan(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf) 2010 2333 { … … 2040 2363 } 2041 2364 2365 /** 2366 * Processes control command from guest. 2367 * See VirtIO 1.0 spec, 5.1.6 "Device Operation" and 5.1.6.5 "Control Virtqueue". 2368 * 2369 * The control command is contained in a virtio buffer pulled from the virtio-net defined control queue (ctrlq). 2370 * Command type is parsed is dispatched to a command-specific device-configuration handler function (e.g. RX, MAC, VLAN, MQ 2371 * and ANNOUNCE). 2372 * 2373 * This function handles all parts of the host-side of the ctrlq round-trip buffer processing. 2374 * 2375 * Invoked by worker for virtio-net defince control queue to process a queued control command buffer. 2376 * 2377 * @param pDevIns PDM device instance 2378 * @param pThis virtio-net device instance 2379 * @param pThisCC virtio-net device instance 2380 * @param pVirtqBuf pointer to buffer pulled from virtq (input to this function) 2381 */ 2042 2382 static void virtioNetR3Ctrl(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 2043 2383 PVIRTQBUF pVirtqBuf) 2044 2384 { 2385 if (!(pThis->fNegotiatedFeatures & VIRTIONET_F_CTRL_VQ)) 2386 LogFunc(("[%s] WARNING: Guest using CTRL queue w/o negotiating VIRTIONET_F_CTRL_VQ feature\n", pThis->szInst)); 2387 2045 2388 LogFunc(("[%s] Received CTRL packet from guest\n", pThis->szInst)); 2046 2389 … … 2099 2442 break; 2100 2443 } 2444 #if FEATURE_OFFERED(STATUS) 2101 2445 pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_ANNOUNCE; 2446 #endif 2102 2447 Log7Func(("[%s] Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst)); 2103 2448 break; … … 2145 2490 } 2146 2491 2147 static int virtioNetR3ReadHeader(PVIRTIOCORE pVirtio, PVIRTIONET pThis, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame) 2492 /** 2493 * Reads virtio-net pkt header from provided Phy. addr of virtio descriptor chain 2494 * (e.g. S/G segment from guest-driver provided buffer pulled from Tx virtq) 2495 * Verifies state and supported modes, sets TCP header size. 2496 * 2497 * @param pVirtio VirtIO core instance data 2498 * @param pThis virtio-net instance 2499 * @param pDevIns PDM device instance 2500 * @param GCPhys Phys. Address from where to read virtio-net pkt header 2501 * @param pPktHdr Where to store read Tx pkt hdr (virtio pkt hdr size is determined from instance configuration) 2502 * @param cbFrame Total pkt frame size to inform bounds check 2503 */ 2504 static int virtioNetR3ReadVirtioTxPktHdr(PVIRTIOCORE pVirtio, PVIRTIONET pThis, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame) 2148 2505 { 2149 2506 int rc = virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys, pPktHdr, pThis->cbPktHdr); … … 2157 2514 if (pPktHdr->uGsoType) 2158 2515 { 2159 uint32_t uMinHdrSize;2160 2161 2516 /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */ 2162 2517 AssertMsgReturn( RT_LIKELY(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM) … … 2164 2519 ("Unsupported ECN request in pkt header\n"), VERR_NOT_SUPPORTED); 2165 2520 2521 uint32_t uTcpHdrSize; 2166 2522 switch (pPktHdr->uGsoType) 2167 2523 { 2168 2524 case VIRTIONET_HDR_GSO_TCPV4: 2169 2525 case VIRTIONET_HDR_GSO_TCPV6: 2170 u MinHdrSize = sizeof(RTNETTCP);2526 uTcpHdrSize = sizeof(RTNETTCP); 2171 2527 break; 2172 2528 case VIRTIONET_HDR_GSO_UDP: 2173 u MinHdrSize = 0;2529 uTcpHdrSize = 0; 2174 2530 break; 2175 2531 default: … … 2178 2534 } 2179 2535 /* Header + MSS must not exceed the packet size. */ 2180 AssertMsgReturn(RT_LIKELY(u MinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGsoSize <= cbFrame),2536 AssertMsgReturn(RT_LIKELY(uTcpHdrSize + pPktHdr->uChksumStart + pPktHdr->uGsoSize <= cbFrame), 2181 2537 ("Header plus message exceeds packet size"), VERR_BUFFER_OVERFLOW); 2182 2538 } … … 2191 2547 } 2192 2548 2549 /** 2550 * Transmits single GSO frame via PDM framework to downstream PDM device, to emit from virtual NIC. 2551 * 2552 * This does final prep of GSO parameters including checksum calculation if configured 2553 * (e.g. if VIRTIONET_HDR_F_NEEDS_CSUM flag is set). 2554 * 2555 * @param pThis virtio-net instance 2556 * @param pThisCC virtio-net instance 2557 * @param pSgBuf PDM S/G buffer containing pkt and hdr to transmit 2558 * @param pGso GSO parameters used for the packet 2559 * @param pPktHdr virtio-net pkt header to adapt to PDM semantics 2560 */ 2193 2561 static int virtioNetR3TransmitFrame(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMSCATTERGATHER pSgBuf, 2194 2562 PPDMNETWORKGSO pGso, PVIRTIONETPKTHDR pPktHdr) 2195 2563 { 2564 2196 2565 virtioNetR3PacketDump(pThis, (uint8_t *)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, "--> Outgoing"); 2197 2566 if (pGso) 2198 2567 { 2199 /* Some guests (RHEL) may report HdrLen excluding transport layer header! */ 2200 /* 2201 * We cannot use cdHdrs provided by the guest because of different ways 2202 * it gets filled out by different versions of kernels. 2203 */ 2204 //if (pGso->cbHdrs < pPktHdr->uCSumStart + pPktHdr->uCSumOffset + 2) 2568 /* Some guests (RHEL) may report HdrLen excluding transport layer header! 2569 * Thus cannot use cdHdrs provided by the guest because of different ways 2570 * it gets filled out by different versions of kernels. */ 2571 Log4Func(("%s HdrLen before adjustment %d.\n", pThis->szInst, pGso->cbHdrsTotal)); 2572 switch (pGso->u8Type) 2205 2573 { 2206 Log4Func(("%s HdrLen before adjustment %d.\n", 2207 pThis->szInst, pGso->cbHdrsTotal)); 2208 switch (pGso->u8Type) 2209 { 2210 case PDMNETWORKGSOTYPE_IPV4_TCP: 2211 case PDMNETWORKGSOTYPE_IPV6_TCP: 2212 pGso->cbHdrsTotal = pPktHdr->uChksumStart + 2213 ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pPktHdr->uChksumStart))->th_off * 4; 2214 2215 AssertMsgReturn(pSgBuf->cbUsed > pGso->cbHdrsTotal, 2216 ("cbHdrsTotal exceeds size of frame"), VERR_BUFFER_OVERFLOW); 2217 2218 pGso->cbHdrsSeg = pGso->cbHdrsTotal; 2219 break; 2220 case PDMNETWORKGSOTYPE_IPV4_UDP: 2221 pGso->cbHdrsTotal = (uint8_t)(pPktHdr->uChksumStart + sizeof(RTNETUDP)); 2222 pGso->cbHdrsSeg = pPktHdr->uChksumStart; 2223 break; 2224 } 2225 /* Update GSO structure embedded into the frame */ 2226 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal; 2227 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg = pGso->cbHdrsSeg; 2228 Log4Func(("%s adjusted HdrLen to %d.\n", 2229 pThis->szInst, pGso->cbHdrsTotal)); 2574 case PDMNETWORKGSOTYPE_IPV4_TCP: 2575 case PDMNETWORKGSOTYPE_IPV6_TCP: 2576 pGso->cbHdrsTotal = pPktHdr->uChksumStart + 2577 ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pPktHdr->uChksumStart))->th_off * 4; 2578 AssertMsgReturn(pSgBuf->cbUsed > pGso->cbHdrsTotal, 2579 ("cbHdrsTotal exceeds size of frame"), VERR_BUFFER_OVERFLOW); 2580 pGso->cbHdrsSeg = pGso->cbHdrsTotal; 2581 break; 2582 case PDMNETWORKGSOTYPE_IPV4_UDP: 2583 pGso->cbHdrsTotal = (uint8_t)(pPktHdr->uChksumStart + sizeof(RTNETUDP)); 2584 pGso->cbHdrsSeg = pPktHdr->uChksumStart; 2585 break; 2230 2586 } 2587 /* Update GSO structure embedded into the frame */ 2588 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal; 2589 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg = pGso->cbHdrsSeg; 2590 Log4Func(("%s adjusted HdrLen to %d.\n", 2591 pThis->szInst, pGso->cbHdrsTotal)); 2231 2592 Log2Func(("%s gso type=%x cbHdrsTotal=%u cbHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n", 2232 2593 pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg, … … 2240 2601 * This is not GSO frame but checksum offloading is requested. 2241 2602 */ 2242 virtioNetR3C ompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed,2603 virtioNetR3Calc16BitChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, 2243 2604 pPktHdr->uChksumStart, pPktHdr->uChksumOffset); 2244 2605 } … … 2247 2608 } 2248 2609 2249 static int virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 2610 /** 2611 * Non-reentrant function transmits all available packets from specified Tx virtq to downstream 2612 * PDM device (if cable is connected). For each Tx pkt, virtio-net pkt header is converted 2613 * to required GSO information (VBox host network stack semantics) 2614 * 2615 * @param pDevIns PDM device instance 2616 * @param pThis virtio-net device instance 2617 * @param pThisCC virtio-net device instance 2618 * @param pTxVirtq Address of transmit virtq 2619 * @param fOnWorkerThread Flag to PDM whether to use caller's or or PDM transmit worker's thread. 2620 */ 2621 static int virtioNetR3TransmitPkts(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 2250 2622 PVIRTIONETVIRTQ pTxVirtq, bool fOnWorkerThread) 2251 2623 { 2252 2253 2624 PVIRTIOCORE pVirtio = &pThis->Virtio; 2254 2625 … … 2268 2639 2269 2640 /* 2270 * Only one thread is allowed to transmit at a time, others should skip 2271 * transmission as the packets will be picked up by the transmitting 2272 * thread. 2641 * Only one thread is allowed to transmit at a time, others should skip transmission as the packets 2642 * will be picked up by the transmitting thread. 2273 2643 */ 2274 2644 if (!ASMAtomicCmpXchgU32(&pThis->uIsTransmitting, 1, 0)) 2275 2645 return VERR_IGNORED; 2276 2277 2278 2646 2279 2647 PPDMINETWORKUP pDrv = pThisCC->pDrv; … … 2288 2656 } 2289 2657 } 2290 2291 2658 int cPkts = virtioCoreVirtqAvailBufCount(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx); 2292 2659 if (!cPkts) … … 2313 2680 PVIRTIOSGSEG paSegsFromGuest = pSgPhysSend->paSegs; 2314 2681 uint32_t cSegsFromGuest = pSgPhysSend->cSegs; 2315 size_t u Size = 0;2682 size_t uFrameSize = 0; 2316 2683 2317 2684 AssertMsgReturn(paSegsFromGuest[0].cbSeg >= pThis->cbPktHdr, … … 2322 2689 AssertMsgReturn(pPktHdr, ("Out of Memory\n"), VERR_NO_MEMORY); 2323 2690 2324 /* Compute total frame size .*/2325 for (unsigned i = 0; i < cSegsFromGuest && u Size < VIRTIONET_MAX_FRAME_SIZE; i++)2326 u Size += paSegsFromGuest[i].cbSeg;2327 2328 Log5Func(("[%s] complete frame is %u bytes.\n", pThis->szInst, u Size));2329 Assert(u Size <= VIRTIONET_MAX_FRAME_SIZE);2691 /* Compute total frame size from guest (including virtio-net pkt hdr) */ 2692 for (unsigned i = 0; i < cSegsFromGuest && uFrameSize < VIRTIONET_MAX_FRAME_SIZE; i++) 2693 uFrameSize += paSegsFromGuest[i].cbSeg; 2694 2695 Log5Func(("[%s] complete frame is %u bytes.\n", pThis->szInst, uFrameSize)); 2696 Assert(uFrameSize <= VIRTIONET_MAX_FRAME_SIZE); 2330 2697 2331 2698 /* Truncate oversized frames. */ 2332 if (u Size > VIRTIONET_MAX_FRAME_SIZE)2333 u Size = VIRTIONET_MAX_FRAME_SIZE;2699 if (uFrameSize > VIRTIONET_MAX_FRAME_SIZE) 2700 uFrameSize = VIRTIONET_MAX_FRAME_SIZE; 2334 2701 2335 2702 if (pThisCC->pDrv) 2336 2703 { 2337 uint64_t uOffset; 2338 2339 uSize -= pThis->cbPktHdr; 2340 rc = virtioNetR3ReadHeader(pVirtio, pThis, pDevIns, paSegsFromGuest[0].GCPhys, pPktHdr, uSize); 2704 uFrameSize -= pThis->cbPktHdr; 2705 /* 2706 * Peel off pkt header and convert to PDM/GSO semantics. 2707 */ 2708 rc = virtioNetR3ReadVirtioTxPktHdr(pVirtio, pThis, pDevIns, paSegsFromGuest[0].GCPhys, pPktHdr, uFrameSize /* cbFrame */); 2341 2709 if (RT_FAILURE(rc)) 2342 2710 return rc; … … 2345 2713 PDMNETWORKGSO Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, pPktHdr); 2346 2714 2715 /* Allocate PDM transmit buffer to send guest provided network frame from to VBox network leaf device */ 2347 2716 PPDMSCATTERGATHER pSgBufToPdmLeafDevice; 2348 rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &pSgBufToPdmLeafDevice); 2717 rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uFrameSize, pGso, &pSgBufToPdmLeafDevice); 2718 2719 /* 2720 * Copy virtio-net guest S/G buffer to PDM leaf driver S/G buffer 2721 * converting from GCphys to virt memory at the same time 2722 */ 2349 2723 if (RT_SUCCESS(rc)) 2350 2724 { … … 2353 2727 2354 2728 size_t cbCopied = 0; 2355 size_t cbTotal = 0; 2356 size_t cbRemain = pSgBufToPdmLeafDevice->cbUsed = uSize; 2357 uOffset = 0; 2729 size_t cbRemain = pSgBufToPdmLeafDevice->cbUsed = uFrameSize; 2730 uint64_t uOffset = 0; 2358 2731 while (cbRemain) 2359 2732 { … … 2369 2742 cbRemain -= cbCopied; 2370 2743 uOffset += cbCopied; 2371 cbTotal += cbCopied;2372 2744 } 2373 2745 2374 LogFunc((".... Copied %lu bytes to %lu byte guest buffer,residual=%lu\n",2375 cbTotal, pVirtqBuf->cbPhysSend, pVirtqBuf->cbPhysSend - cbTotal));2746 LogFunc((".... Copied %lu/%lu bytes to %lu byte guest buffer. Buf residual=%lu\n", 2747 uOffset, uFrameSize, pVirtqBuf->cbPhysSend, virtioCoreGCPhysChainCalcLengthLeft(pSgPhysSend))); 2376 2748 2377 2749 rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, pPktHdr); … … 2388 2760 else 2389 2761 { 2390 Log4Func(("Failed to allocate S/G buffer: size=%u rc=%Rrc\n", uSize, rc));2762 Log4Func(("Failed to allocate S/G buffer: frame size=%u rc=%Rrc\n", uFrameSize, rc)); 2391 2763 /* Stop trying to fetch TX descriptors until we get more bandwidth. */ 2392 2764 virtioCoreR3VirtqBufRelease(pVirtio, pVirtqBuf); … … 2394 2766 } 2395 2767 2396 /* Point to next descriptor chain in avail ring of virtq */2397 2768 virtioCoreR3VirtqAvailBufNext(pVirtio, pTxVirtq->uIdx); 2398 2769 2399 2770 /* No data to return to guest, but necessary to put elem (e.g. desc chain head idx) on used ring */ 2400 2771 virtioCoreR3VirtqUsedBufPut(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx, NULL, pVirtqBuf, true /* fFence */); 2401 2402 /* Update used ring idx and notify guest that we've transmitted the data it sent */2403 2772 virtioCoreVirtqUsedRingSync(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx); 2404 2773 } … … 2428 2797 STAM_COUNTER_INC(&pThis->StatTransmitByNetwork); 2429 2798 2430 (void)virtioNetR3TransmitP endingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);2799 (void)virtioNetR3TransmitPkts(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/); 2431 2800 } 2432 2801 … … 2438 2807 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 2439 2808 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2440 RT_NOREF(hTimer, pvUser);2441 2809 2442 2810 SET_LINK_UP(pThis); 2443 2444 2811 virtioNetWakeupRxBufWaiter(pDevIns); 2445 2446 LogFunc(("[%s] Link is up\n", pThis->szInst));2447 2812 2448 2813 if (pThisCC->pDrv) 2449 2814 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP); 2450 } 2451 2452 /** 2453 * Takes down the link temporarily if it's current status is up. 2815 2816 LogFunc(("[%s] Link is up\n", pThis->szInst)); 2817 RT_NOREF(hTimer, pvUser); 2818 } 2819 2820 /** 2821 * Takes down the link temporarily if its current status is up. 2454 2822 * 2455 2823 * This is used during restore and when replumbing the network link. … … 2465 2833 static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2466 2834 { 2467 2468 2835 if (IS_LINK_UP(pThis)) 2469 2836 { 2470 2837 SET_LINK_DOWN(pThis); 2471 2838 2472 /* Re store the link back in 5 seconds. */2839 /* Re-establish link in 5 seconds. */ 2473 2840 int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay); 2474 2841 AssertRC(rc); … … 2489 2856 bool fRequestedLinkStateIsUp = (enmState == PDMNETWORKLINKSTATE_UP); 2490 2857 2858 #ifdef LOG_ENABLED 2491 2859 if (LogIs7Enabled()) 2492 2860 { … … 2507 2875 } 2508 2876 } 2877 #endif 2509 2878 2510 2879 if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME) 2511 2880 { 2512 2513 2881 if (IS_LINK_UP(pThis)) 2514 2882 { … … 2582 2950 } 2583 2951 2952 /** 2953 * Creates a worker for specified queue, along with semaphore to throttle the worker. 2954 * 2955 * @param pDevIns - PDM device instance 2956 * @param pThis - virtio-net instance 2957 * @param pWorker - Pointer to worker state 2958 * @param pWorkerR3 - Pointer to worker state 2959 * @param pVirtq - Pointer to virtq 2960 */ 2584 2961 static int virtioNetR3CreateOneWorkerThread(PPDMDEVINS pDevIns, PVIRTIONET pThis, 2585 2962 PVIRTIONETWORKER pWorker, PVIRTIONETWORKERR3 pWorkerR3, … … 2590 2967 2591 2968 int rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pWorker->hEvtProcess); 2592 LogFunc(("PDMDevHlpSUPSemEventCreate(pDevIns, &pWorker->hEvtProcess=%p)", &pWorker->hEvtProcess));2593 LogFunc(("pWorker->hEvtProcess = %x\n", pWorker->hEvtProcess));2594 2969 2595 2970 if (RT_FAILURE(rc)) … … 2606 2981 N_("Error creating thread for Virtual Virtq %s\n"), pVirtq->uIdx); 2607 2982 2608 pWorker->fAssigned = true; /* Because worker's state held in fixed-size arrayw/empty slots */2983 pWorker->fAssigned = true; /* Because worker's state in fixed-size array initialized w/empty slots */ 2609 2984 2610 2985 LogFunc(("%s pThread: %p\n", pVirtq->szName, pWorkerR3->pThread)); … … 2618 2993 int rc; 2619 2994 2620 2621 /* Create the Control Queue worker anyway whether or not it is feature-negotiated or utilized by the guest, 2622 * as it's relatively low overhead resource-wise. This is for two reasons: First, at the time of this comment 2623 * queues and workers are configured pre-feature negotiation; secondly, legacy guest drivers are allowed to start 2624 * using the device prior to feature negotiation, and we can only know we are dealing with a modern guest driver 2625 * after feature negotiation. */ 2995 /* Create the Control Queue worker anyway whether or not it is feature-negotiated or utilized by the guest. 2996 * See related comment for queue construction in the device constructor function for more context. 2997 */ 2626 2998 2627 2999 PVIRTIONETVIRTQ pCtlVirtq = &pThis->aVirtqs[CTRLQIDX]; … … 2651 3023 2652 3024 return rc; 3025 } 3026 3027 static void virtioNetConfigurePktHdr(PVIRTIONET pThis, uint32_t fLegacy) 3028 { 3029 /* Calculate network packet header type and size based on what we know now */ 3030 pThis->cbPktHdr = sizeof(VIRTIONETPKTHDR); 3031 if (!fLegacy) 3032 /* Modern (e.g. >= VirtIO 1.0) device specification's pkt size rules */ 3033 if (FEATURE_ENABLED(MRG_RXBUF)) 3034 pThis->ePktHdrType = kVirtioNetModernPktHdrWithMrgRx; 3035 else /* Modern guest driver with MRG_RX feature disabled */ 3036 pThis->ePktHdrType = kVirtioNetModernPktHdrWithoutMrgRx; 3037 else 3038 { 3039 /* Legacy (e.g. < VirtIO 1.0) device specification's pkt size rules */ 3040 if (FEATURE_ENABLED(MRG_RXBUF)) 3041 pThis->ePktHdrType = kVirtioNetLegacyPktHdrWithMrgRx; 3042 else /* Legacy guest with MRG_RX feature disabled */ 3043 { 3044 pThis->ePktHdrType = kVirtioNetLegacyPktHdrWithoutMrgRx; 3045 pThis->cbPktHdr -= RT_SIZEOFMEMB(VIRTIONETPKTHDR, uNumBuffers); 3046 } 3047 } 2653 3048 } 2654 3049 … … 2682 3077 if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pVirtq->uIdx)) 2683 3078 { 2684 /* Atomic interlocks avoid missing alarm while going to sleep & notifier waking the awoken */ 3079 /* Precisely coordinated atomic interlocks avoid a race condition that results in hung thread 3080 * wherein a sloppily coordinated wake-up notification during a transition into or out 3081 * of sleep leaves notifier and target mutually confused about actual & intended state. 3082 */ 2685 3083 ASMAtomicWriteBool(&pWorker->fSleeping, true); 2686 2687 3084 bool fNotificationSent = ASMAtomicXchgBool(&pWorker->fNotified, false); 2688 3085 if (!fNotificationSent) … … 2701 3098 } 2702 3099 ASMAtomicWriteBool(&pWorker->fSleeping, false); 2703 2704 3100 } 2705 2706 /* Dispatch to the handler for the queue this worker is set up to drive */2707 3101 /* 3102 * Dispatch to the handler for the queue this worker is set up to drive 3103 */ 2708 3104 if (pVirtq->fCtlVirtq) 2709 3105 { … … 2713 3109 if (rc == VERR_NOT_AVAILABLE) 2714 3110 { 2715 Log10Func(("[%s] %s worker woken. Nothing found in queue /n", pThis->szInst, pVirtq->szName));3111 Log10Func(("[%s] %s worker woken. Nothing found in queue\n", pThis->szInst, pVirtq->szName)); 2716 3112 continue; 2717 3113 } … … 2722 3118 { 2723 3119 Log10Func(("[%s] %s worker woken. Virtq has data to transmit\n", pThis->szInst, pVirtq->szName)); 2724 virtioNetR3TransmitP endingPackets(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */);3120 virtioNetR3TransmitPkts(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */); 2725 3121 } 2726 2727 /* Rx queues aren't handled by our worker threads. Instead, the PDM network 2728 * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback, 2729 * which waits until woken by virtioNetVirtqNotified() 3122 /* Note: Surprise! Rx queues aren't handled by local worker threads. Instead, the PDM network leaf driver 3123 * invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback, which waits until woken by virtioNetVirtqNotified() 2730 3124 * indicating that guest IN buffers have been added to Rx virt queue. 2731 3125 */ … … 2735 3129 } 2736 3130 2737 2738 3131 /** 2739 3132 * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged} 3133 * 3134 * Called back by the core code when VirtIO's ready state has changed. 2740 3135 */ 2741 3136 static DECLCALLBACK(void) virtioNetR3StatusChg(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady) … … 2748 3143 if (fVirtioReady) 2749 3144 { 2750 Log(("-----------------------------------------------------------------------------------------\n")); 2751 Log(("%-23s: %s *** VirtIO Ready ***\n-----------------------------------------------------------------------------------------\n", 2752 __FUNCTION__, pThis->szInst)); 2753 3145 #ifdef LOG_ENABLED 3146 Log(("\n%-23s: %s *** VirtIO Ready ***\n\n", __FUNCTION__, pThis->szInst)); 3147 virtioCorePrintDeviceFeatures(&pThis->Virtio, NULL, s_aDevSpecificFeatures, RT_ELEMENTS(s_aDevSpecificFeatures)); 3148 #endif 3149 pThis->fResetting = false; 2754 3150 pThis->fNegotiatedFeatures = virtioCoreGetNegotiatedFeatures(pVirtio); 2755 #ifdef LOG_ENABLED2756 virtioCorePrintDeviceFeatures(&pThis->Virtio, NULL, s_aDevSpecificFeatures,2757 RT_ELEMENTS(s_aDevSpecificFeatures));2758 #endif2759 2760 3151 pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0; 2761 2762 pThis->fResetting = false;2763 3152 2764 3153 for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) … … 2780 3169 else 2781 3170 { 2782 Log((" %-23s: %s VirtIO is resetting\n", __FUNCTION__, pThis->szInst));3171 Log(("\n%-23s: %s VirtIO is resetting ***\n", __FUNCTION__, pThis->szInst)); 2783 3172 2784 3173 pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0; … … 2802 3191 2803 3192 for (uint16_t uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) 3193 { 3194 virtioCoreR3VirtqDetach(&pThis->Virtio, uVirtqNbr); 2804 3195 pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore = false; 2805 } 2806 } 2807 2808 static DECLCALLBACK(void) virtioGuestVersionHandler(PVIRTIOCORE pVirtio, uint32_t fModern) 2809 { 2810 LogFunc(("Guest Driver version is %s\n", fModern ? "modern" : "legacy")); 2811 2812 PVIRTIONET pThis = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio); 2813 2814 /* Calculate network packet header type and size based on what we know now */ 2815 pThis->cbPktHdr = sizeof(VIRTIONETPKTHDR); 2816 2817 if (fModern) 2818 pThis->ePktHdrType = kVirtioNetModernPktHdr_1_0; 2819 else if (FEATURE_DISABLED(MRG_RXBUF)) 2820 { 2821 pThis->ePktHdrType = kVirtioNetLegacyPktHdrWithoutMrgRx; 2822 pThis->cbPktHdr -= RT_SIZEOFMEMB(VIRTIONETPKTHDR, uNumBuffers); 2823 } 2824 else /* Legacy guest with MRG_RX feature enabled */ 2825 pThis->ePktHdrType = kVirtioNetLegacyPktHdr; 2826 } 2827 3196 } 3197 } 3198 } 3199 3200 /** 3201 * @callback_method_impl{VIRTIOCORER3,pfnFeatureNegotiationComplete} 3202 */ 3203 static DECLCALLBACK(void) pfnFeatureNegotiationComplete(PVIRTIOCORE pVirtio, uint64_t fDriverFeatures, uint32_t fLegacy) 3204 { 3205 PVIRTIONET pThis = PDMDEVINS_2_DATA(pVirtio->pDevInsR3, PVIRTIONET); 3206 3207 LogFunc(("[Feature Negotiation Complete] Guest Driver version is: %s\n", fLegacy ? "legacy" : "modern")); 3208 virtioNetConfigurePktHdr(pThis, fLegacy); 3209 virtioNetR3SetVirtqNames(pThis, fLegacy); 3210 3211 /* Senseless for modern guest to use control queue in this case. (See Note 1 in PDM-invoked device constructor) */ 3212 if (!fLegacy && !(fDriverFeatures & VIRTIONET_F_CTRL_VQ)) 3213 virtioNetR3VirtqDestroy(pVirtio, &pThis->aVirtqs[CTRLQIDX]); 3214 } 2828 3215 2829 3216 #endif /* IN_RING3 */ … … 2832 3219 * @interface_method_impl{PDMDEVREGR3,pfnDetach} 2833 3220 * 2834 * One harddisk at one port has been unplugged.2835 3221 * The VM is suspended at this point. 2836 3222 */ … … 2861 3247 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2862 3248 2863 RT_NOREF(fFlags);2864 2865 3249 Log7Func(("[%s]", pThis->szInst)); 2866 2867 3250 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN); 2868 2869 RT_NOREF(pThis);2870 3251 2871 3252 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "Network Port"); … … 2880 3261 Log(("[%s] No attached driver!\n", pThis->szInst)); 2881 3262 3263 RT_NOREF2(pThis, fFlags); 2882 3264 return rc; 2883 3265 } … … 2894 3276 return VINF_SUCCESS; 2895 3277 } 2896 2897 3278 2898 3279 /** … … 2920 3301 2921 3302 Log(("[%s] Destroying instance\n", pThis->szInst)); 2922 2923 3303 if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT) 2924 3304 { … … 2929 3309 2930 3310 virtioNetR3DestroyWorkerThreads(pDevIns, pThis, pThisCC); 2931 2932 3311 virtioCoreR3Term(pDevIns, &pThis->Virtio, &pThisCC->Virtio); 2933 2934 3312 return VINF_SUCCESS; 2935 3313 } … … 2937 3315 /** 2938 3316 * @interface_method_impl{PDMDEVREGR3,pfnConstruct} 3317 * 3318 * Notes about revising originally VirtIO 1.0+ only virtio-net device emulator to be "transitional", 3319 * a VirtIO term meaning this now interoperates with both "legacy" (e.g. pre-1.0) and "modern" (1.0+) 3320 * guest virtio-net drivers. The changes include migrating VMs saved using prior DevVirtioNet.cpp (0.95) 3321 * saveExec/loadExec semantics to use 1.0 save/load semantics. 3322 * 3323 * Regardless of the 1.0 spec's overall helpful guidance for implementing transitional devices, 3324 * A bit is left to the imagination, e.g. some things have to be determined deductively 3325 * (AKA "the hard way"). 3326 * 3327 * Case in point: According to VirtIO 0.95 ("legacy") specification, section 2.2.1, "historically" 3328 * drivers may start driving prior to feature negotiation and prior to drivers setting DRIVER_OK 3329 * status, "provided driver doesn't use features that alter early use of this device". That 3330 * is Interpreted here to mean a virtio-net driver must respect default settings (such as implicit 3331 * pkt header default size, as determined per Note 1 below). 3332 * 3333 * ---------------------------------------------------------------------------------------------- 3334 * Transitional device initialization Note 1: Identifying default value for network Rx pkt hdr size. 3335 * (VirtIO 1.0 specification section 5.1.6.1) 3336 * 3337 * Guest virtio legacy drivers may begin operations prematurely, regardless of early spec's 3338 * initialization sequence (see note 2 below). Legacy drivers implicitly default to using the 3339 * (historically) shortest-length network packet header *unless* VIRTIONET_F_MRG_RXBUF feature is 3340 * negotiated. If feature negotiation phase is [optionally] enacted by a legacy guest (i.e. we strictly 3341 * enforce full initialization protocol for modern guests), virtioNetConfigurePktHdr() is invoked again to 3342 * finalize device's network packet header size. Best-guess at default packet header size is deduced, e.g. 3343 * isn't documented, as follows: A legacy guest with VIRTIONET_F_MRG_RXBUF not-yet-negotiated is the only 3344 * case where network I/O could possibly occur with any reasonable assumption about packet type/size, 3345 * because logically other permutations couldn't possibly be inferred until feature negotiation 3346 * is complete. Specifically, those cases are: 3347 * 3348 * 1. A modern driver (detected only when VIRTIONET_F_VERSION_1 feature is ack'd by guest, and, 3349 * simultaneously, VIRTIONET_F_MRG_RXBUF feature is accepted or declined (determining network receive-packet 3350 * processing behavior). 3351 * 3352 * 2. A legacy driver that has agreed to use VIRTIONET_F_MRG_RXBUF feature, resulting in a two-byte larger pkt hdr, 3353 * (as well as deciding Rx packet processing behavior). 3354 * 3355 * ---------------------------------------------------------------------------------------------- 3356 * Transitional device initialization Note 2: Creating unnegotiated control queue. 3357 * (VirtIO 1.0 spec, sections 5.1.5 and 5.1.6.5) 3358 * 3359 * Create all queues immediately, prior to feature negotiation, including control queue (irrespective 3360 * of the fact it's too early in initialization for control feature to be approved by guest). This 3361 * transitional device must deal with legacy guests which *can* (and on linux have been seen to) use 3362 * the control queue prior to feature negotiation. 3363 * 3364 * The initial assumption is *modern" guest virtio-net drivers out in the wild could never reasonably 3365 * attempt something as obviously risky as using ctrlq without first acking VIRTIO_NET_F_CTRL_VQ 3366 * feature to establish it. For now, we create the control queue proactively to accomodate a potentially 3367 * badly behaved but officially sanctioned legacy virtio-net driver, but *destroy* that same queue 3368 * if a driver announces as 'modern' during feature finalization yet leaves VIRTIO_NET_F_CTRL_VQ un-ack'd. 2939 3369 */ 2940 3370 static DECLCALLBACK(int) virtioNetR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) … … 2946 3376 2947 3377 /* 2948 * Quick initialization of the state data, making sure that the destructor always works.3378 * Quickly initialize state data to ensure destructor always works. 2949 3379 */ 2950 3380 Log7Func(("PDM device instance: %d\n", iInstance)); 2951 3381 RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "virtio-net #%d", iInstance); 2952 3382 2953 pThisCC->pDevIns = pDevIns;2954 pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface;2955 pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed;3383 pThisCC->pDevIns = pDevIns; 3384 pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface; 3385 pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed; 2956 3386 pThisCC->led.u32Magic = PDMLED_MAGIC; 2957 3387 … … 2970 3400 * Validate configuration. 2971 3401 */ 2972 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|CableConnected|LineSpeed|LinkUpDelay|StatNo ", "");3402 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|CableConnected|LineSpeed|LinkUpDelay|StatNo|Legacy", ""); 2973 3403 2974 3404 /* Get config params */ … … 3014 3444 # endif 3015 3445 3016 pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS;3017 pThisCC->Virtio.pfn GuestVersionHandler = virtioGuestVersionHandler;3018 pThisCC->Virtio.pfnVirtqNotified = virtioNetVirtqNotified;3019 pThisCC->Virtio.pfnStatusChanged = virtioNetR3StatusChg;3020 pThisCC->Virtio.pfnDevCapRead = virtioNetR3DevCapRead;3021 pThisCC->Virtio.pfnDevCapWrite = virtioNetR3DevCapWrite;3446 pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS; 3447 pThisCC->Virtio.pfnFeatureNegotiationComplete = pfnFeatureNegotiationComplete; 3448 pThisCC->Virtio.pfnVirtqNotified = virtioNetVirtqNotified; 3449 pThisCC->Virtio.pfnStatusChanged = virtioNetR3StatusChg; 3450 pThisCC->Virtio.pfnDevCapRead = virtioNetR3DevCapRead; 3451 pThisCC->Virtio.pfnDevCapWrite = virtioNetR3DevCapWrite; 3022 3452 3023 3453 VIRTIOPCIPARAMS VirtioPciParams; 3024 VirtioPciParams.uDeviceId = PCI_DEVICE_ID_VIRTIONET_HOST;3025 VirtioPciParams.uClassBase = PCI_CLASS_BASE_NETWORK_CONTROLLER;3026 VirtioPciParams.uClassSub = PCI_CLASS_SUB_NET_ETHERNET_CONTROLLER;3027 VirtioPciParams.uClassProg = PCI_CLASS_PROG_UNSPECIFIED;3028 VirtioPciParams.uSubsystemId = PCI_DEVICE_ID_VIRTIONET_HOST; /* VirtIO 1.0 allows PCI Device ID here */3029 VirtioPciParams.uInterruptLine = 0x00;3030 VirtioPciParams.uInterruptPin = 0x01;3454 VirtioPciParams.uDeviceId = PCI_DEVICE_ID_VIRTIONET_HOST; 3455 VirtioPciParams.uClassBase = PCI_CLASS_BASE_NETWORK_CONTROLLER; 3456 VirtioPciParams.uClassSub = PCI_CLASS_SUB_NET_ETHERNET_CONTROLLER; 3457 VirtioPciParams.uClassProg = PCI_CLASS_PROG_UNSPECIFIED; 3458 VirtioPciParams.uSubsystemId = PCI_DEVICE_ID_VIRTIONET_HOST; /* VirtIO 1.0 allows PCI Device ID here */ 3459 VirtioPciParams.uInterruptLine = 0x00; 3460 VirtioPciParams.uInterruptPin = 0x01; 3031 3461 3032 3462 /* Create semaphore used to synchronize/throttle the downstream LUN's Rx waiter thread. */ … … 3035 3465 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore")); 3036 3466 3037 3038 /* Initialize VirtIO core. (pfnStatusChanged callback when both host VirtIO core & guest driver are ready) */ 3467 pThis->fOfferLegacy = VIRTIONET_TRANSITIONAL_ENABLE_FLAG; 3468 virtioNetConfigurePktHdr(pThis, pThis->fOfferLegacy); /* set defaults */ 3469 3470 /* Initialize VirtIO core. (*pfnStatusChanged)() callback occurs when both host VirtIO core & guest driver are ready) */ 3039 3471 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst, 3040 VIRTIONET_HOST_FEATURES_OFFERED, 3472 VIRTIONET_HOST_FEATURES_OFFERED, pThis->fOfferLegacy, 3041 3473 &pThis->virtioNetConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioNetConfig)); 3042 3474 if (RT_FAILURE(rc)) … … 3046 3478 if (!virtioNetValidateRequiredFeatures(pThis->fNegotiatedFeatures)) 3047 3479 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated.")); 3048 3049 3050 /* 3051 * Initialize queues. Due to this being a transitional device (e.g. accommodating both modern 3052 * and legacy drivers), the control queue must be created whether or not the VIRTIO_NET_F_CTRL_VQ 3053 * is negotiated, because legacy drivers are not bound to begin configuration and I/O until 3054 * feature negotiation is complete. In the final analysis, there may be no good reason to 3055 * enforce VIRTIO_NET_F_CTRL_VQ as a prerequisite to handling guest control queue transactions, 3056 * but merely to log violations (e.g. control transactions without feature explicitly enabled), 3057 * once, thus not being strict with regard to misbehaving modern drivers. 3058 */ 3059 3060 pThis->cVirtqPairs = 1; /* default, VirtIO 1.0, 5.1.6.5.5 */ 3480 pThis->cVirtqPairs = pThis->virtioNetConfig.uMaxVirtqPairs; 3061 3481 pThis->cVirtqs += pThis->cVirtqPairs * 2 + 1; 3062 3482 pThis->aVirtqs[CTRLQIDX].fCtlVirtq = true; 3063 3483 3064 virtioNetR3SetVirtqNames(pThis );3484 virtioNetR3SetVirtqNames(pThis, pThis->fOfferLegacy); 3065 3485 for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++) 3066 3486 { … … 3068 3488 PVIRTIONETWORKER pWorker = &pThis->aWorkers[uVirtqNbr]; 3069 3489 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[uVirtqNbr]; 3070 pVirtq->uIdx = uVirtqNbr; 3071 pWorker->uIdx = uVirtqNbr; 3072 pWorkerR3->uIdx = uVirtqNbr; 3490 pVirtq->uIdx = pWorker->uIdx = pWorkerR3->uIdx = uVirtqNbr; 3073 3491 } 3074 3492 /* … … 3099 3517 AssertRCReturn(rc, rc); 3100 3518 } 3101 3102 3519 /* 3103 3520 * Status driver … … 3109 3526 3110 3527 pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pUpBase, PDMILEDCONNECTORS); 3111 3112 3528 /* 3113 3529 * Register saved state. 3114 3530 */ 3115 rc = PDMDevHlpSSMRegister(pDevIns, VIRTIONET_SAVED _STATE_VERSION, sizeof(*pThis),3116 virtioNetR3 SaveExec, virtioNetR3LoadExec);3531 rc = PDMDevHlpSSMRegister(pDevIns, VIRTIONET_SAVEDSTATE_VERSION, sizeof(*pThis), 3532 virtioNetR3ModernSaveExec, virtioNetR3ModernDeviceLoadExec); 3117 3533 AssertRCReturn(rc, rc); 3118 3119 /* 3534 /* 3120 3535 * Statistics and debug stuff. 3121 3536 * The /Public/ bits are official and used by session info in the GUI. … … 3144 3559 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTransmitByThread, STAMTYPE_COUNTER, "Transmit/ByThread", STAMUNIT_COUNT, "Thread-initiated transmissions"); 3145 3560 # endif 3146 3147 3561 /* 3148 3562 * Register the debugger info callback (ignore errors). … … 3174 3588 * The device registration structure. 3175 3589 */ 3176 const PDMDEVREG g_DeviceVirtioNet _1_0=3590 const PDMDEVREG g_DeviceVirtioNet = 3177 3591 { 3178 3592 /* .uVersion = */ PDM_DEVREG_VERSION, 3179 3593 /* .uReserved0 = */ 0, 3180 /* .szName = */ "virtio-net -1-dot-0",3594 /* .szName = */ "virtio-net", 3181 3595 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE | PDM_DEVREG_FLAGS_RZ, 3182 3596 /* .fClass = */ PDM_DEVREG_CLASS_NETWORK, -
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r91920 r92939 1996 1996 * Call the virtio core to let it load its state. 1997 1997 */ 1998 rc = virtioCoreR3LoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM); 1998 rc = virtioCoreR3ModernDeviceLoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, 1999 uVersion, VIRTIOSCSI_SAVED_STATE_VERSION, pThis->virtioScsiConfig.uNumVirtqs); 1999 2000 2000 2001 /* … … 2087 2088 * Call the virtio core to let it save its state. 2088 2089 */ 2089 return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM );2090 return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, VIRTIOSCSI_SAVED_STATE_VERSION, VIRTIOSCSI_VIRTQ_CNT); 2090 2091 } 2091 2092 … … 2469 2470 2470 2471 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInstance, 2471 VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED, 2472 VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED, 0 /*fOfferLegacy*/, 2472 2473 &pThis->virtioScsiConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioScsiConfig)); 2473 2474 if (RT_FAILURE(rc)) -
trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp
r92091 r92939 42 42 * Defined Constants And Macros * 43 43 *********************************************************************************************************************************/ 44 44 45 #define INSTANCE(a_pVirtio) ((a_pVirtio)->szInstance) 45 46 #define VIRTQNAME(a_pVirtio, a_uVirtq) ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName) 46 47 47 48 48 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \ 49 49 (virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq) == 0) 50 50 51 52 51 #define IS_DRIVER_OK(a_pVirtio) ((a_pVirtio)->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 53 52 #define WAS_DRIVER_OK(a_pVirtio) ((a_pVirtio)->fPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 53 54 /** 55 * These defines are used to track guest virtio-net driver writing driver features accepted flags 56 * in two 32-bit operations (in arbitrary order), and one bit dedicated to ensured 'features complete' 57 * is handled once. 58 */ 59 #define DRIVER_FEATURES_0_WRITTEN 1 /**< fDriverFeatures[0] written by guest virtio-net */ 60 #define DRIVER_FEATURES_1_WRITTEN 2 /**< fDriverFeatures[1] written by guest virtio-net */ 61 #define DRIVER_FEATURES_0_AND_1_WRITTEN 3 /**< Both 32-bit parts of fDriverFeatures[] written */ 62 #define DRIVER_FEATURES_COMPLETE_HANDLED 4 /**< Features negotiation complete handler called */ 54 63 55 64 /** … … 68 77 69 78 70 /** Marks the start of the virtio saved state (just for sanity). */71 #define VIRTIO_SAVEDSTATE_MARKER UINT64_C(0x1133557799bbddff)72 /** The current saved state version for the virtio core. */73 #define VIRTIO_SAVEDSTATE_VERSION UINT32_C(1)74 75 76 79 /********************************************************************************************************************************* 77 80 * Structures and Typedefs * 78 81 *********************************************************************************************************************************/ 79 80 82 81 83 /** @name virtq related flags … … 90 92 91 93 /** 92 * virtq 93 * (struct names follow VirtIO 1.0 spec, typedef use VBox style)94 * virtq-related structs 95 * (struct names follow VirtIO 1.0 spec, field names use VBox styled naming, w/respective spec'd name in comments) 94 96 */ 95 97 typedef struct virtq_desc … … 125 127 } VIRTQ_USED_T, *PVIRTQ_USED_T; 126 128 127 128 129 const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState) 129 130 { … … 141 142 142 143 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq); 143 static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec); 144 static int virtioNudgeGuest(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec); 145 146 DECLINLINE(uint16_t) virtioCoreR3CountPendingBufs(uint16_t uRingIdx, uint16_t uShadowIdx, uint16_t uQueueSize) 147 { 148 if (uShadowIdx == uRingIdx) 149 return 0; 150 else 151 if (uShadowIdx > uRingIdx) 152 return uShadowIdx - uRingIdx; 153 return uQueueSize - (uRingIdx - uShadowIdx); 154 } 144 155 145 156 /** @name Internal queue operations … … 156 167 uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */ 157 168 158 159 160 169 virtioCoreGCPhysRead(pVirtio, pDevIns, 170 pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems), 171 pDesc, sizeof(VIRTQ_DESC_T)); 161 172 } 162 173 #endif … … 207 218 pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags), 208 219 &fFlags, sizeof(fFlags)); 209 210 220 return fFlags; 211 221 } … … 249 259 } 250 260 251 252 261 #ifdef IN_RING3 253 262 DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq) … … 289 298 290 299 if (uIdxActual < uIdxShadow) 291 uIdxDelta = (uIdxActual + VIRTQ_SIZE) - uIdxShadow;300 uIdxDelta = (uIdxActual + pVirtq->uQueueSize) - uIdxShadow; 292 301 else 293 302 uIdxDelta = uIdxActual - uIdxShadow; 294 295 LogFunc(("%s, %u %s\n",296 pVirtq->szName, uIdxDelta, uIdxDelta == 1 ? "entry" : "entries"));297 303 298 304 return uIdxDelta; … … 320 326 if (!pVirtio->fLegacyDriver && !pVirtq->uEnable) 321 327 { 322 LogRelFunc(("virtq: % d (%s) not enabled\n", uVirtq, VIRTQNAME(pVirtio, uVirtq)));328 LogRelFunc(("virtq: %s not enabled\n", VIRTQNAME(pVirtio, uVirtq))); 323 329 return 0; 324 330 } 325 326 331 return virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq); 327 332 } … … 440 445 else 441 446 cbPrint = RTStrPrintf(pszOut, cbRemain, "%02x %s", c, (col + 1) % 8 ? "" : " "); 442 447 ADJCURSOR(cbPrint); 443 448 } 444 449 for (uint16_t idx = row * 16; idx < row * 16 + 16; idx++) … … 456 461 #undef ADJCURSOR 457 462 } 458 #endif /* LOG_ENABLED */ 459 460 /** API function: See header file */ 461 int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio) 462 { 463 Log12Func(("%s", pVirtio->fLegacyDriver ? "Legacy Guest Driver handling mode\n" : "")); 464 return pVirtio->fLegacyDriver; 465 } 463 466 464 467 465 /** API function: See header file */ … … 470 468 int fHasIndex, uint32_t idx) 471 469 { 472 if (!LogIs6Enabled()) 473 return; 474 475 char szIdx[16]; 476 if (fHasIndex) 477 RTStrPrintf(szIdx, sizeof(szIdx), "[%d]", idx); 478 else 479 szIdx[0] = '\0'; 480 481 if (cb == 1 || cb == 2 || cb == 4 || cb == 8) 482 { 483 char szDepiction[64]; 484 size_t cchDepiction; 485 if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */ 486 cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s[%d:%d]", 487 pszMember, szIdx, uOffset, uOffset + cb - 1); 470 if (LogIs6Enabled()) 471 { 472 char szIdx[16]; 473 if (fHasIndex) 474 RTStrPrintf(szIdx, sizeof(szIdx), "[%d]", idx); 488 475 else 489 cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s", pszMember, szIdx); 490 491 /* padding */ 492 if (cchDepiction < 30) 493 szDepiction[cchDepiction++] = ' '; 494 while (cchDepiction < 30) 495 szDepiction[cchDepiction++] = '.'; 496 szDepiction[cchDepiction] = '\0'; 497 498 RTUINT64U uValue; 499 uValue.u = 0; 500 memcpy(uValue.au8, pv, cb); 501 Log6(("%-23s: Guest %s %s %#0*RX64\n", 502 pszFunc, fWrite ? "wrote" : "read ", szDepiction, 2 + cb * 2, uValue.u)); 503 } 504 else /* odd number or oversized access, ... log inline hex-dump style */ 505 { 506 Log6(("%-23s: Guest %s %s%s[%d:%d]: %.*Rhxs\n", 507 pszFunc, fWrite ? "wrote" : "read ", pszMember, 508 szIdx, uOffset, uOffset + cb, cb, pv)); 476 szIdx[0] = '\0'; 477 478 if (cb == 1 || cb == 2 || cb == 4 || cb == 8) 479 { 480 char szDepiction[64]; 481 size_t cchDepiction; 482 if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */ 483 cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s[%d:%d]", 484 pszMember, szIdx, uOffset, uOffset + cb - 1); 485 else 486 cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s", pszMember, szIdx); 487 488 /* padding */ 489 if (cchDepiction < 30) 490 szDepiction[cchDepiction++] = ' '; 491 while (cchDepiction < 30) 492 szDepiction[cchDepiction++] = '.'; 493 szDepiction[cchDepiction] = '\0'; 494 495 RTUINT64U uValue; 496 uValue.u = 0; 497 memcpy(uValue.au8, pv, cb); 498 Log6(("%-23s: Guest %s %s %#0*RX64\n", 499 pszFunc, fWrite ? "wrote" : "read ", szDepiction, 2 + cb * 2, uValue.u)); 500 } 501 else /* odd number or oversized access, ... log inline hex-dump style */ 502 { 503 Log6(("%-23s: Guest %s %s%s[%d:%d]: %.*Rhxs\n", 504 pszFunc, fWrite ? "wrote" : "read ", pszMember, 505 szIdx, uOffset, uOffset + cb, cb, pv)); 506 } 509 507 } 510 508 RT_NOREF2(fWrite, pszFunc); … … 512 510 513 511 /** 514 * Makes the MMIO-mapped Virtio fDeviceStatus registers non-cryptic (buffers to 515 * keep the output clean during multi-threaded activity) 512 * Log MMIO-mapped Virtio fDeviceStatus register bitmask, naming the bits 516 513 */ 517 514 DECLINLINE(void) virtioCoreFormatDeviceStatus(uint8_t bStatus, char *pszBuf, size_t uSize) 518 515 { 519 520 #define ADJCURSOR(len) cp += len; uSize -= len; sep = (char *)" | "; 521 516 # define ADJCURSOR(len) { cp += len; uSize -= len; sep = (char *)" | "; } 522 517 memset(pszBuf, 0, uSize); 523 size_t len; 524 char *cp = pszBuf; 525 char *sep = (char *)""; 526 527 if (bStatus == 0) { 518 char *cp = pszBuf, *sep = (char *)""; 519 int len; 520 if (bStatus == 0) 528 521 RTStrPrintf(cp, uSize, "RESET"); 529 return; 530 } 531 if (bStatus & VIRTIO_STATUS_ACKNOWLEDGE) 532 { 533 len = RTStrPrintf(cp, uSize, "ACKNOWLEDGE"); 534 ADJCURSOR(len); 535 } 536 if (bStatus & VIRTIO_STATUS_DRIVER) 537 { 538 len = RTStrPrintf(cp, uSize, "%sDRIVER", sep); 539 ADJCURSOR(len); 540 } 541 if (bStatus & VIRTIO_STATUS_FEATURES_OK) 542 { 543 len = RTStrPrintf(cp, uSize, "%sFEATURES_OK", sep); 544 ADJCURSOR(len); 545 } 546 if (bStatus & VIRTIO_STATUS_DRIVER_OK) 547 { 548 len = RTStrPrintf(cp, uSize, "%sDRIVER_OK", sep); 549 ADJCURSOR(len); 550 } 551 if (bStatus & VIRTIO_STATUS_FAILED) 552 { 553 len = RTStrPrintf(cp, uSize, "%sFAILED", sep); 554 ADJCURSOR(len); 555 } 556 if (bStatus & VIRTIO_STATUS_DEVICE_NEEDS_RESET) 557 RTStrPrintf(cp, uSize, "%sNEEDS_RESET", sep); 558 559 #undef ADJCURSOR 522 else 523 { 524 if (bStatus & VIRTIO_STATUS_ACKNOWLEDGE) 525 { 526 len = RTStrPrintf(cp, uSize, "ACKNOWLEDGE"); 527 ADJCURSOR(len); 528 } 529 if (bStatus & VIRTIO_STATUS_DRIVER) 530 { 531 len = RTStrPrintf(cp, uSize, "%sDRIVER", sep); 532 ADJCURSOR(len); 533 } 534 if (bStatus & VIRTIO_STATUS_FEATURES_OK) 535 { 536 len = RTStrPrintf(cp, uSize, "%sFEATURES_OK", sep); 537 ADJCURSOR(len); 538 } 539 if (bStatus & VIRTIO_STATUS_DRIVER_OK) 540 { 541 len = RTStrPrintf(cp, uSize, "%sDRIVER_OK", sep); 542 ADJCURSOR(len); 543 } 544 if (bStatus & VIRTIO_STATUS_FAILED) 545 { 546 len = RTStrPrintf(cp, uSize, "%sFAILED", sep); 547 ADJCURSOR(len); 548 } 549 if (bStatus & VIRTIO_STATUS_DEVICE_NEEDS_RESET) 550 RTStrPrintf(cp, uSize, "%sNEEDS_RESET", sep); 551 } 552 # undef ADJCURSOR 553 } 554 555 #endif /* LOG_ENABLED */ 556 557 /** API function: See header file */ 558 int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio) 559 { 560 return pVirtio->fLegacyDriver; 560 561 } 561 562 … … 570 571 pVirtq->uUsedIdxShadow = 0; 571 572 pVirtq->fUsedRingEvent = false; 573 pVirtq->fAttached = true; 572 574 RTStrCopy(pVirtq->szName, sizeof(pVirtq->szName), pcszName); 573 575 return VINF_SUCCESS; 576 } 577 578 int virtioCoreR3VirtqDetach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 579 { 580 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtqNbr]; 581 pVirtq->uVirtq = 0; 582 pVirtq->uAvailIdxShadow = 0; 583 pVirtq->uUsedIdxShadow = 0; 584 pVirtq->fUsedRingEvent = false; 585 pVirtq->fAttached = false; 586 memset(pVirtq->szName, 0, sizeof(pVirtq->szName)); 587 return VINF_SUCCESS; 588 } 589 590 bool virtioCoreR3VirtqIsAttached(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 591 { 592 return pVirtio->aVirtqueues[uVirtqNbr].fAttached; 593 } 594 595 bool virtioCoreR3VirtqIsEnabled(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr) 596 { 597 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtqNbr]; 598 return (bool)pVirtq->uEnable && pVirtq->GCPhysVirtqDesc; 574 599 } 575 600 … … 582 607 583 608 /** @todo add ability to dump physical contents described by any descriptor (using existing VirtIO core API function) */ 584 // 609 // bool fDump = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)" 585 610 586 611 uint16_t uAvailIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtq); … … 648 673 pHlp->pfnPrintf(pHlp, " No desc chains available\n"); 649 674 pHlp->pfnPrintf(pHlp, "\n"); 650 651 675 } 652 676 … … 661 685 return cRefs; 662 686 } 663 664 687 665 688 /** API Function: See header file */ … … 687 710 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio) 688 711 { 689 virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig); 690 } 712 virtioNudgeGuest(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig); 713 } 714 691 715 692 716 /** API Function: See header file */ 693 717 void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtq, bool fEnable) 694 718 { 695 696 719 Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues)); 697 720 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq]; … … 719 742 if (!pVirtio->fLegacyDriver) 720 743 pVirtio->fGenUpdatePending = true; 721 virtio Kick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);744 virtioNudgeGuest(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig); 722 745 } 723 746 } … … 748 771 return VINF_SUCCESS; 749 772 } 750 751 773 752 774 /** API Function: See header file */ … … 797 819 { 798 820 PVIRTIOSGSEG pSeg; 799 800 821 /* 801 822 * Malicious guests may go beyond paSegsIn or paSegsOut boundaries by linking … … 804 825 * the following aborts I/O if breach and employs a simple log throttling algorithm to notify. 805 826 */ 806 if (cSegsIn + cSegsOut >= VIRTQ_SIZE)827 if (cSegsIn + cSegsOut >= pVirtq->uQueueSize) 807 828 { 808 829 static volatile uint32_t s_cMessages = 0; … … 823 844 if (desc.fFlags & VIRTQ_DESC_F_WRITE) 824 845 { 825 Log6Func(("%s IN idx=% u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));846 Log6Func(("%s IN idx=%-4u seg=%-3u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb)); 826 847 cbIn += desc.cb; 827 848 pSeg = &paSegsIn[cSegsIn++]; … … 829 850 else 830 851 { 831 Log6Func(("%s OUT desc_idx=% u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));852 Log6Func(("%s OUT desc_idx=%-4u seg=%-3u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb)); 832 853 cbOut += desc.cb; 833 854 pSeg = &paSegsOut[cSegsOut++]; … … 840 861 #endif 841 862 } 842 843 863 pSeg->GCPhys = desc.GCPhysBuf; 844 864 pSeg->cbSeg = desc.cb; 845 846 865 uDescIdx = desc.uDescIdxNext; 847 866 } while (desc.fFlags & VIRTQ_DESC_F_NEXT); … … 915 934 AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 916 935 917 Log6Func((" Copying device data to %s (%s guest), desc chain idx %d\n",918 VIRTQNAME(pVirtio, uVirtq), pVirt io->fLegacyDriver ? "legacy" : "modern", virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));919 920 /* Copy s/g buf (virtual memory) to guest phys mem ( INdirection). */936 Log6Func((" Copying device data to %s, [desc:%u → used ring:%u]\n", 937 VIRTQNAME(pVirtio, uVirtq), pVirtqBuf->uHeadIdx, pVirtq->uUsedIdxShadow)); 938 939 /* Copy s/g buf (virtual memory) to guest phys mem (VirtIO "IN" direction). */ 921 940 922 941 size_t cbCopy = 0, cbTotal = 0, cbRemain = 0; … … 944 963 } 945 964 946 /* If this write-ahead crosses threshold where the driver wants to get an event, flag it*/965 /* Flag if write-ahead crosses threshold where guest driver indicated it wants event notification */ 947 966 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 948 967 if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq)) … … 951 970 /* 952 971 * Place used buffer's descriptor in used ring but don't update used ring's slot index. 953 * That will be done with a subsequent client call to virtioCoreVirtqUsedRingSync() */ 972 * That will be done with a subsequent client call to virtioCoreVirtqUsedRingSync() 973 */ 954 974 virtioWriteUsedElem(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow++, pVirtqBuf->uHeadIdx, (uint32_t)cbTotal); 955 975 956 if (pSgVirtReturn) 957 Log6Func((" ... %d segs, %zu bytes, copied to %u byte buf. residual: %zu bytes\n", 958 pSgVirtReturn->cSegs, cbTotal - cbRemain, pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal)); 959 960 Log6Func((" %s used_idx=%u\n", VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq))); 976 #ifdef LOG_ENABLED 977 if (LogIs6Enabled() && pSgVirtReturn) 978 { 979 980 LogFunc((" ... %d segs, %zu bytes, copied to %u byte buf@offset=%u. Residual: %zu bytes\n", 981 pSgVirtReturn->cSegs, cbTotal - cbRemain, pVirtqBuf->cbPhysReturn, 982 ((virtioCoreGCPhysChainCalcBufSize(pVirtqBuf->pSgPhysReturn) - 983 virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn)) - (cbTotal - cbRemain)), 984 virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn) )); 985 986 uint16_t uPending = virtioCoreR3CountPendingBufs( 987 virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq), 988 pVirtq->uUsedIdxShadow, pVirtq->uQueueSize); 989 990 LogFunc((" %u used buf%s not synced in %s\n", uPending, uPending == 1 ? "" : "s ", 991 VIRTQNAME(pVirtio, uVirtq))); 992 } 993 #endif 994 return VINF_SUCCESS; 995 } 996 997 /** API function: See Header file */ 998 int virtioCoreR3VirtqUsedBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq, 999 size_t cb, void const *pv, PVIRTQBUF pVirtqBuf, uint32_t cbEnqueue, bool fFence) 1000 { 1001 Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues)); 1002 Assert(pv); 1003 1004 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq]; 1005 PVIRTIOSGBUF pSgPhysReturn = pVirtqBuf->pSgPhysReturn; 1006 1007 Assert(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC); 1008 Assert(pVirtqBuf->cRefs > 0); 1009 1010 AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 1011 1012 Log6Func((" Copying device data to %s, [desc chain head idx:%u]\n", 1013 VIRTQNAME(pVirtio, uVirtq), pVirtqBuf->uHeadIdx)); 1014 1015 /* 1016 * Convert virtual memory simple buffer to guest physical memory (VirtIO descriptor chain) 1017 */ 1018 uint8_t *pvBuf = (uint8_t *)pv; 1019 size_t cbRemain = cb, cbCopy = 0; 1020 while (cbRemain) 1021 { 1022 cbCopy = RT_MIN(pSgPhysReturn->cbSegLeft, cbRemain); 1023 Assert(cbCopy > 0); 1024 virtioCoreGCPhysWrite(pVirtio, pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pvBuf, cbCopy); 1025 virtioCoreGCPhysChainAdvance(pSgPhysReturn, cbCopy); 1026 pvBuf += cbCopy; 1027 cbRemain -= cbCopy; 1028 } 1029 LogFunc((" ...%zu bytes, copied to %u byte buf@offset=%u. Residual: %zu bytes\n", 1030 cb , pVirtqBuf->cbPhysReturn, 1031 ((virtioCoreGCPhysChainCalcBufSize(pVirtqBuf->pSgPhysReturn) - 1032 virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn)) - cb), 1033 virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn))); 1034 1035 if (cbEnqueue) 1036 { 1037 if (fFence) 1038 { 1039 RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */ 1040 Assert(!(cbCopy >> 32)); 1041 } 1042 /* Flag if write-ahead crosses threshold where guest driver indicated it wants event notification */ 1043 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 1044 if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq)) 1045 pVirtq->fUsedRingEvent = true; 1046 /* 1047 * Place used buffer's descriptor in used ring but don't update used ring's slot index. 1048 * That will be done with a subsequent client call to virtioCoreVirtqUsedRingSync() 1049 */ 1050 Log6Func((" Enqueue desc chain head idx %u to %s used ring @ %u\n", pVirtqBuf->uHeadIdx, 1051 VIRTQNAME(pVirtio, uVirtq), pVirtq->uUsedIdxShadow)); 1052 1053 virtioWriteUsedElem(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow++, pVirtqBuf->uHeadIdx, cbEnqueue); 1054 1055 #ifdef LOG_ENABLED 1056 if (LogIs6Enabled()) 1057 { 1058 uint16_t uPending = virtioCoreR3CountPendingBufs( 1059 virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq), 1060 pVirtq->uUsedIdxShadow, pVirtq->uQueueSize); 1061 1062 LogFunc((" %u used buf%s not synced in %s\n", 1063 uPending, uPending == 1 ? "" : "s ", VIRTQNAME(pVirtio, uVirtq))); 1064 } 1065 #endif 1066 } /* fEnqueue */ 961 1067 962 1068 return VINF_SUCCESS; … … 976 1082 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 977 1083 978 Log6Func((" %s ++used_idx=%u\n", pVirtq->szName, pVirtq->uUsedIdxShadow)); 1084 Log6Func((" Sync %s used ring (%u → idx)\n", 1085 pVirtq->szName, pVirtq->uUsedIdxShadow)); 979 1086 980 1087 virtioWriteUsedRingIdx(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow); … … 998 1105 PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC); 999 1106 1000 /* See VirtIO 1.0, section 4.1.5.2 It implies that uVirtq and uNotifyIdx should match. 1001 * Disregarding this notification may cause throughput to stop, however there's no way to know 1002 * which was queue was intended for wake-up if the two parameters disagree. */ 1003 1107 /* VirtIO 1.0, section 4.1.5.2 implies uVirtq and uNotifyIdx should match. Disregarding any of 1108 * these notifications (if those indicies disagree) may break device/driver synchronization, 1109 * causing eternal throughput starvation, yet there's no specified way to disambiguate 1110 * which queue to wake-up in any awkward situation where the two parameters differ. 1111 */ 1004 1112 AssertMsg(uNotifyIdx == uVirtq, 1005 1113 ("Guest kicked virtq %d's notify addr w/non-corresponding virtq idx %d\n", … … 1010 1118 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq]; 1011 1119 1012 Log6Func(("%s (desc chains: %u)\n", pVirtq->szName,1120 Log6Func(("%s: (desc chains: %u)\n", pVirtq->szName ? pVirtq->szName : "?UNAMED QUEUE?", 1013 1121 virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq))); 1014 1122 … … 1048 1156 pVirtq->szName, (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq))); 1049 1157 #endif 1050 virtio Kick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);1158 virtioNudgeGuest(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector); 1051 1159 pVirtq->fUsedRingEvent = false; 1052 1160 return; … … 1062 1170 if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, pVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT)) 1063 1171 { 1064 virtio Kick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);1172 virtioNudgeGuest(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector); 1065 1173 return; 1066 1174 } … … 1077 1185 * @param uVec MSI-X vector, if enabled 1078 1186 */ 1079 static int virtio Kick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector)1187 static int virtioNudgeGuest(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector) 1080 1188 { 1081 1189 if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT) 1082 Log6Func((" reason:buffer added to 'used' ring.\n"));1190 Log6Func(("Reason for interrupt - buffer added to 'used' ring.\n")); 1083 1191 else 1084 1192 if (uCause == VIRTIO_ISR_DEVICE_CONFIG) 1085 Log6Func((" reason:device config change\n"));1193 Log6Func(("Reason for interrupt - device config change\n")); 1086 1194 1087 1195 if (!pVirtio->fMsiSupport) … … 1132 1240 { 1133 1241 LogFunc(("Resetting device VirtIO state\n")); 1134 pVirtio->fLegacyDriver = 1; /* Assume this.Cleared if VIRTIO_F_VERSION_1 feature ack'd */1242 pVirtio->fLegacyDriver = pVirtio->fOfferLegacy; /* Cleared if VIRTIO_F_VERSION_1 feature ack'd */ 1135 1243 pVirtio->uDeviceFeaturesSelect = 0; 1136 1244 pVirtio->uDriverFeaturesSelect = 0; … … 1168 1276 } 1169 1277 #endif /* IN_RING3 */ 1278 1279 /* 1280 * Determines whether guest virtio driver is modern or legacy and does callback 1281 * informing device-specific code that feature negotiation is complete. 1282 * Should be called only once (coordinated via the 'toggle' flag) 1283 */ 1284 #ifdef IN_RING3 1285 DECLINLINE(void) virtioR3DoFeaturesCompleteOnceOnly(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC) 1286 { 1287 if (pVirtio->uDriverFeatures & VIRTIO_F_VERSION_1) 1288 { 1289 LogFunc(("VIRTIO_F_VERSION_1 feature ack'd by guest\n")); 1290 pVirtio->fLegacyDriver = 0; 1291 } 1292 else 1293 { 1294 if (pVirtio->fOfferLegacy) 1295 { 1296 pVirtio->fLegacyDriver = 1; 1297 LogFunc(("VIRTIO_F_VERSION_1 feature was NOT set by guest\n")); 1298 } 1299 else 1300 AssertMsgFailed(("Guest didn't accept VIRTIO_F_VERSION_1, but fLegacyOffered flag not set.\n")); 1301 } 1302 pVirtioCC->pfnFeatureNegotiationComplete(pVirtio, pVirtio->uDriverFeatures, pVirtio->fLegacyDriver); 1303 pVirtio->fDriverFeaturesWritten |= DRIVER_FEATURES_COMPLETE_HANDLED; 1304 } 1305 #endif 1170 1306 1171 1307 /** … … 1228 1364 case 0: 1229 1365 memcpy(&pVirtio->uDriverFeatures, pv, cb); 1366 pVirtio->fDriverFeaturesWritten |= DRIVER_FEATURES_0_WRITTEN; 1367 LogFunc(("Set DRIVER_FEATURES_0_WRITTEN. pVirtio->fDriverFeaturesWritten=%d\n", pVirtio->fDriverFeaturesWritten)); 1368 if ( (pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_0_AND_1_WRITTEN) == DRIVER_FEATURES_0_AND_1_WRITTEN 1369 && !(pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_COMPLETE_HANDLED)) 1370 #ifdef IN_RING0 1371 return VINF_IOM_R3_MMIO_WRITE; 1372 #endif 1373 #ifdef IN_RING3 1374 virtioR3DoFeaturesCompleteOnceOnly(pVirtio, pVirtioCC); 1375 #endif 1230 1376 VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess); 1231 1377 break; 1232 1378 case 1: 1233 1379 memcpy((char *)&pVirtio->uDriverFeatures + sizeof(uint32_t), pv, cb); 1234 if (pVirtio->uDriverFeatures & VIRTIO_F_VERSION_1) 1235 { 1380 pVirtio->fDriverFeaturesWritten |= DRIVER_FEATURES_1_WRITTEN; 1381 LogFunc(("Set DRIVER_FEATURES_1_WRITTEN. pVirtio->fDriverFeaturesWritten=%d\n", pVirtio->fDriverFeaturesWritten)); 1382 if ( (pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_0_AND_1_WRITTEN) == DRIVER_FEATURES_0_AND_1_WRITTEN 1383 && !(pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_COMPLETE_HANDLED)) 1236 1384 #ifdef IN_RING0 1237 1385 return VINF_IOM_R3_MMIO_WRITE; 1238 1386 #endif 1239 1387 #ifdef IN_RING3 1240 pVirtio->fLegacyDriver = 0; 1241 pVirtioCC->pfnGuestVersionHandler(pVirtio, 1 /* fModern */); 1242 #endif 1243 } 1388 virtioR3DoFeaturesCompleteOnceOnly(pVirtio, pVirtioCC); 1389 #endif 1244 1390 VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess + sizeof(uint32_t)); 1245 1391 break; … … 1389 1535 * This I/O handler exists only to handle access from legacy drivers. 1390 1536 */ 1391 1392 1537 static DECLCALLBACK(VBOXSTRICTRC) virtioLegacyIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb) 1393 1538 { 1394 1395 1539 PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE); 1396 1540 STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatRead), a); 1397 1541 1398 1542 RT_NOREF(pvUser); 1543 Log(("%-23s: Port read at offset=%RTiop, cb=%#x%s", 1544 __FUNCTION__, offPort, cb, 1545 VIRTIO_DEV_CONFIG_MATCH_MEMBER(fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort) ? "" : "\n")); 1399 1546 1400 1547 void *pv = pu32; /* To use existing macros */ … … 1412 1559 if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort)) 1413 1560 { 1414 uint32_t val = pVirtio->uDriverFeatures & 0xffffffff;1561 uint32_t val = pVirtio->uDriverFeatures & UINT32_C(0xffffffff); 1415 1562 memcpy(pu32, &val, cb); 1416 1563 VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort); … … 1420 1567 { 1421 1568 *(uint8_t *)pu32 = pVirtio->fDeviceStatus; 1422 1423 1569 if (LogIs7Enabled()) 1424 1570 { … … 1435 1581 pVirtio->uISR = 0; 1436 1582 virtioLowerInterrupt( pDevIns, 0); 1437 Log((" ISR read and cleared\n"));1583 Log((" (ISR read and cleared)\n")); 1438 1584 } 1439 1585 else … … 1482 1628 return rc; 1483 1629 } 1484 1485 1630 STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a); 1486 1631 return VINF_SUCCESS; 1487 1632 } 1488 1489 1633 1490 1634 /** … … 1504 1648 int fWrite = 1; /* To use existing macros */ 1505 1649 1506 // LogFunc(("Write to port offset=%RTiop, cb=%#x, u32=%#x\n",offPort, cb, u32));1650 Log(("%-23s: Port written at offset=%RTiop, cb=%#x, u32=%#x\n", __FUNCTION__, offPort, cb, u32)); 1507 1651 1508 1652 if (VIRTIO_DEV_CONFIG_MATCH_MEMBER( uVirtqSelect, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort)) … … 1535 1679 pVirtio->uDriverFeatures &= VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED; 1536 1680 } 1681 if (!((pVirtio->fDriverFeaturesWritten ^= 1) & 1)) 1682 { 1683 #ifdef IN_RING0 1684 Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__)); 1685 return VINF_IOM_R3_MMIO_WRITE; 1686 #endif 1687 #ifdef IN_RING3 1688 PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC); 1689 virtioR3DoFeaturesCompleteOnceOnly(pVirtio, pVirtioCC); 1690 #endif 1691 } 1537 1692 VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort); 1538 1693 } … … 1556 1711 Log(("%-23s: Guest wrote fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut)); 1557 1712 } 1558 1559 1713 if (fDriverStateImproved || fDriverInitiatedReset) 1560 1714 { … … 1693 1847 1694 1848 /* 1695 * A dditionally, anytime any part of the device-specific configuration (which our client maintains)1696 * is READ it needs to be checked to see if it changed since the last time any part was read, in1697 * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1)1849 * Anytime any part of the dev-specific dev config (which this virtio core implementation sees 1850 * as a blob, and virtio dev-specific code separates into fields) is READ, it must be compared 1851 * for deltas from previous read to maintain a config gen. seq. counter (VirtIO 1.0, section 4.1.4.3.1) 1698 1852 */ 1699 1853 bool fDevSpecificFieldChanged = RT_BOOL(memcmp(pVirtioCC->pbDevSpecificCfg + uOffset, … … 1706 1860 { 1707 1861 ++pVirtio->uConfigGeneration; 1708 Log6Func(("Bumped cfg. generation to %d because %s%s\n", 1709 pVirtio->uConfigGeneration, 1862 Log6Func(("Bumped cfg. generation to %d because %s%s\n", pVirtio->uConfigGeneration, 1710 1863 fDevSpecificFieldChanged ? "<dev cfg changed> " : "", 1711 1864 pVirtio->fGenUpdatePending ? "<update was pending>" : "")); … … 1769 1922 #else 1770 1923 STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a); 1924 Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__)); 1771 1925 return VINF_IOM_R3_MMIO_WRITE; 1772 1926 #endif … … 1819 1973 if (uAddress == pVirtio->uPciCfgDataOff) 1820 1974 { 1821 /* 1822 * VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability 1823 * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space 1824 * (the virtio_pci_cfg_cap capability), and access data items. 1825 * This is used by BIOS to gain early boot access to the the storage device. 1826 */ 1975 /* See comments in PCI Cfg capability initialization (in capabilities setup section of this code) */ 1827 1976 struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap; 1828 1977 uint32_t uLength = pPciCap->uLength; … … 1863 2012 if (uAddress == pVirtio->uPciCfgDataOff) 1864 2013 { 1865 /* VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability 1866 * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space 1867 * (the virtio_pci_cfg_cap capability), and access data items. 1868 * This is used by BIOS to gain early boot access to the the storage device.*/ 1869 2014 /* See comments in PCI Cfg capability initialization (in capabilities setup section of this code) */ 1870 2015 struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap; 1871 2016 uint32_t uLength = pPciCap->uLength; … … 1889 2034 1890 2035 /********************************************************************************************************************************* 1891 * Saved state .*2036 * Saved state (SSM) * 1892 2037 *********************************************************************************************************************************/ 2038 2039 2040 /** 2041 * Loads a saved device state (called from device-specific code on SSM final pass) 2042 * 2043 * @param pVirtio Pointer to the shared virtio state. 2044 * @param pHlp The ring-3 device helpers. 2045 * @param pSSM The saved state handle. 2046 * @returns VBox status code. 2047 */ 2048 int virtioCoreR3LegacyDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, 2049 PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uVirtioLegacy_3_1_Beta) 2050 { 2051 int rc; 2052 uint32_t uDriverFeaturesLegacy32bit; 2053 2054 rc = pHlp->pfnSSMGetU32( pSSM, &uDriverFeaturesLegacy32bit); 2055 AssertRCReturn(rc, rc); 2056 pVirtio->uDriverFeatures = (uint64_t)uDriverFeaturesLegacy32bit; 2057 2058 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtio->uVirtqSelect); 2059 AssertRCReturn(rc, rc); 2060 2061 rc = pHlp->pfnSSMGetU8( pSSM, &pVirtio->fDeviceStatus); 2062 AssertRCReturn(rc, rc); 2063 2064 char szOut[80] = { 0 }; 2065 virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut)); 2066 Log(("Loaded legacy device status = (%s)\n", szOut)); 2067 2068 rc = pHlp->pfnSSMGetU8( pSSM, &pVirtio->uISR); 2069 AssertRCReturn(rc, rc); 2070 2071 uint32_t cQueues = 3; /* Thes constant default value copied from earliest v0.9 code */ 2072 if (uVersion > uVirtioLegacy_3_1_Beta) 2073 { 2074 rc = pHlp->pfnSSMGetU32(pSSM, &cQueues); 2075 AssertRCReturn(rc, rc); 2076 } 2077 2078 AssertLogRelMsgReturn(cQueues <= VIRTQ_MAX_COUNT, ("%#x\n", cQueues), VERR_SSM_LOAD_CONFIG_MISMATCH); 2079 AssertLogRelMsgReturn(pVirtio->uVirtqSelect < cQueues || (cQueues == 0 && pVirtio->uVirtqSelect), 2080 ("uVirtqSelect=%u cQueues=%u\n", pVirtio->uVirtqSelect, cQueues), 2081 VERR_SSM_LOAD_CONFIG_MISMATCH); 2082 2083 Log(("\nRestoring %d legacy-only virtio-net device queues from saved state:\n", cQueues)); 2084 for (unsigned uVirtq = 0; uVirtq < cQueues; uVirtq++) 2085 { 2086 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq]; 2087 2088 if (uVirtq == cQueues - 1) 2089 RTStrPrintf(pVirtq->szName, sizeof(pVirtq->szName), "legacy-ctrlq"); 2090 else if (uVirtq % 2) 2091 RTStrPrintf(pVirtq->szName, sizeof(pVirtq->szName), "legacy-xmitq<%d>", uVirtq / 2); 2092 else 2093 RTStrPrintf(pVirtq->szName, sizeof(pVirtq->szName), "legacy-recvq<%d>", uVirtq / 2); 2094 2095 rc = pHlp->pfnSSMGetU16(pSSM, &pVirtq->uQueueSize); 2096 AssertRCReturn(rc, rc); 2097 2098 uint32_t uVirtqPfn; 2099 rc = pHlp->pfnSSMGetU32(pSSM, &uVirtqPfn); 2100 AssertRCReturn(rc, rc); 2101 2102 rc = pHlp->pfnSSMGetU16(pSSM, &pVirtq->uAvailIdxShadow); 2103 AssertRCReturn(rc, rc); 2104 2105 rc = pHlp->pfnSSMGetU16(pSSM, &pVirtq->uUsedIdxShadow); 2106 AssertRCReturn(rc, rc); 2107 2108 if (uVirtqPfn) 2109 { 2110 pVirtq->GCPhysVirtqDesc = (uint64_t)uVirtqPfn * VIRTIO_PAGE_SIZE; 2111 pVirtq->GCPhysVirtqAvail = pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * pVirtq->uQueueSize; 2112 pVirtq->GCPhysVirtqUsed = 2113 RT_ALIGN(pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uQueueSize]), VIRTIO_PAGE_SIZE); 2114 pVirtq->uEnable = 1; 2115 } 2116 else 2117 { 2118 LogFunc(("WARNING: QUEUE \"%s\" PAGE NUMBER ZERO IN SAVED STATE\n", pVirtq->szName)); 2119 pVirtq->uEnable = 0; 2120 } 2121 pVirtq->uNotifyOffset = 0; /* unused in legacy mode */ 2122 pVirtq->uMsixVector = 0; /* unused in legacy mode */ 2123 } 2124 pVirtio->fGenUpdatePending = 0; /* unused in legacy mode */ 2125 pVirtio->uConfigGeneration = 0; /* unused in legacy mode */ 2126 pVirtio->uPciCfgDataOff = 0; /* unused in legacy mode (port I/O used instead) */ 2127 2128 return VINF_SUCCESS; 2129 } 2130 2131 /** 2132 * Loads a saved device state (called from device-specific code on SSM final pass) 2133 * 2134 * Note: This loads state saved by a Modern (VirtIO 1.0+) device, of which this transitional device is one, 2135 * and thus supports both legacy and modern guest virtio drivers. 2136 * 2137 * @param pVirtio Pointer to the shared virtio state. 2138 * @param pHlp The ring-3 device helpers. 2139 * @param pSSM The saved state handle. 2140 * @returns VBox status code. 2141 */ 2142 int virtioCoreR3ModernDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uTestVersion, uint32_t cQueues) 2143 { 2144 RT_NOREF2(cQueues, uVersion); 2145 LogFunc(("\n")); 2146 /* 2147 * Check the marker and (embedded) version number. 2148 */ 2149 uint64_t uMarker = 0; 2150 int rc; 2151 2152 rc = pHlp->pfnSSMGetU64(pSSM, &uMarker); 2153 AssertRCReturn(rc, rc); 2154 if (uMarker != VIRTIO_SAVEDSTATE_MARKER) 2155 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS, 2156 N_("Expected marker value %#RX64 found %#RX64 instead"), 2157 VIRTIO_SAVEDSTATE_MARKER, uMarker); 2158 uint32_t uVersionSaved = 0; 2159 rc = pHlp->pfnSSMGetU32(pSSM, &uVersionSaved); 2160 AssertRCReturn(rc, rc); 2161 if (uVersionSaved != uTestVersion) 2162 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS, 2163 N_("Unsupported virtio version: %u"), uVersionSaved); 2164 /* 2165 * Load the state. 2166 */ 2167 rc = pHlp->pfnSSMGetU32( pSSM, &pVirtio->fLegacyDriver); 2168 AssertRCReturn(rc, rc); 2169 rc = pHlp->pfnSSMGetBool( pSSM, &pVirtio->fGenUpdatePending); 2170 AssertRCReturn(rc, rc); 2171 rc = pHlp->pfnSSMGetU8( pSSM, &pVirtio->fDeviceStatus); 2172 AssertRCReturn(rc, rc); 2173 rc = pHlp->pfnSSMGetU8( pSSM, &pVirtio->uConfigGeneration); 2174 AssertRCReturn(rc, rc); 2175 rc = pHlp->pfnSSMGetU8( pSSM, &pVirtio->uPciCfgDataOff); 2176 AssertRCReturn(rc, rc); 2177 rc = pHlp->pfnSSMGetU8( pSSM, &pVirtio->uISR); 2178 AssertRCReturn(rc, rc); 2179 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtio->uVirtqSelect); 2180 AssertRCReturn(rc, rc); 2181 rc = pHlp->pfnSSMGetU32( pSSM, &pVirtio->uDeviceFeaturesSelect); 2182 AssertRCReturn(rc, rc); 2183 rc = pHlp->pfnSSMGetU32( pSSM, &pVirtio->uDriverFeaturesSelect); 2184 AssertRCReturn(rc, rc); 2185 rc = pHlp->pfnSSMGetU64( pSSM, &pVirtio->uDriverFeatures); 2186 AssertRCReturn(rc, rc); 2187 2188 /** @todo Adapt this loop use cQueues argument instead of static queue count (safely with SSM versioning) */ 2189 for (uint32_t i = 0; i < VIRTQ_MAX_COUNT; i++) 2190 { 2191 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[i]; 2192 rc = pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqDesc); 2193 AssertRCReturn(rc, rc); 2194 rc = pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqAvail); 2195 AssertRCReturn(rc, rc); 2196 rc = pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqUsed); 2197 AssertRCReturn(rc, rc); 2198 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtq->uNotifyOffset); 2199 AssertRCReturn(rc, rc); 2200 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtq->uMsixVector); 2201 AssertRCReturn(rc, rc); 2202 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtq->uEnable); 2203 AssertRCReturn(rc, rc); 2204 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtq->uQueueSize); 2205 AssertRCReturn(rc, rc); 2206 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtq->uAvailIdxShadow); 2207 AssertRCReturn(rc, rc); 2208 rc = pHlp->pfnSSMGetU16( pSSM, &pVirtq->uUsedIdxShadow); 2209 AssertRCReturn(rc, rc); 2210 rc = pHlp->pfnSSMGetMem( pSSM, pVirtq->szName, sizeof(pVirtq->szName)); 2211 AssertRCReturn(rc, rc); 2212 } 2213 return VINF_SUCCESS; 2214 } 1893 2215 1894 2216 /** … … 1900 2222 * @returns VBox status code. 1901 2223 */ 1902 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM) 1903 { 2224 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t cQueues) 2225 { 2226 RT_NOREF(cQueues); 2227 /** @todo figure out a way to save cQueues (with SSM versioning) */ 2228 1904 2229 LogFunc(("\n")); 1905 2230 pHlp->pfnSSMPutU64(pSSM, VIRTIO_SAVEDSTATE_MARKER); 1906 pHlp->pfnSSMPutU32(pSSM, VIRTIO_SAVEDSTATE_VERSION); 1907 2231 pHlp->pfnSSMPutU32(pSSM, uVersion); 2232 2233 pHlp->pfnSSMPutU32( pSSM, pVirtio->fLegacyDriver); 1908 2234 pHlp->pfnSSMPutBool(pSSM, pVirtio->fGenUpdatePending); 1909 2235 pHlp->pfnSSMPutU8( pSSM, pVirtio->fDeviceStatus); … … 1932 2258 AssertRCReturn(rc, rc); 1933 2259 } 1934 1935 return VINF_SUCCESS;1936 }1937 1938 /**1939 * Called from the FNSSMDEVLOADEXEC function of the device.1940 *1941 * @param pVirtio Pointer to the shared virtio state.1942 * @param pHlp The ring-3 device helpers.1943 * @param pSSM The saved state handle.1944 * @returns VBox status code.1945 */1946 int virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)1947 {1948 LogFunc(("\n"));1949 /*1950 * Check the marker and (embedded) version number.1951 */1952 uint64_t uMarker = 0;1953 int rc = pHlp->pfnSSMGetU64(pSSM, &uMarker);1954 AssertRCReturn(rc, rc);1955 if (uMarker != VIRTIO_SAVEDSTATE_MARKER)1956 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,1957 N_("Expected marker value %#RX64 found %#RX64 instead"),1958 VIRTIO_SAVEDSTATE_MARKER, uMarker);1959 uint32_t uVersion = 0;1960 rc = pHlp->pfnSSMGetU32(pSSM, &uVersion);1961 AssertRCReturn(rc, rc);1962 if (uVersion != VIRTIO_SAVEDSTATE_VERSION)1963 return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,1964 N_("Unsupported virtio version: %u"), uVersion);1965 /*1966 * Load the state.1967 */1968 pHlp->pfnSSMGetBool( pSSM, &pVirtio->fGenUpdatePending);1969 pHlp->pfnSSMGetU8( pSSM, &pVirtio->fDeviceStatus);1970 pHlp->pfnSSMGetU8( pSSM, &pVirtio->uConfigGeneration);1971 pHlp->pfnSSMGetU8( pSSM, &pVirtio->uPciCfgDataOff);1972 pHlp->pfnSSMGetU8( pSSM, &pVirtio->uISR);1973 pHlp->pfnSSMGetU16( pSSM, &pVirtio->uVirtqSelect);1974 pHlp->pfnSSMGetU32( pSSM, &pVirtio->uDeviceFeaturesSelect);1975 pHlp->pfnSSMGetU32( pSSM, &pVirtio->uDriverFeaturesSelect);1976 pHlp->pfnSSMGetU64( pSSM, &pVirtio->uDriverFeatures);1977 1978 for (uint32_t i = 0; i < VIRTQ_MAX_COUNT; i++)1979 {1980 PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[i];1981 1982 pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqDesc);1983 pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqAvail);1984 pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqUsed);1985 pHlp->pfnSSMGetU16( pSSM, &pVirtq->uNotifyOffset);1986 pHlp->pfnSSMGetU16( pSSM, &pVirtq->uMsixVector);1987 pHlp->pfnSSMGetU16( pSSM, &pVirtq->uEnable);1988 pHlp->pfnSSMGetU16( pSSM, &pVirtq->uQueueSize);1989 pHlp->pfnSSMGetU16( pSSM, &pVirtq->uAvailIdxShadow);1990 pHlp->pfnSSMGetU16( pSSM, &pVirtq->uUsedIdxShadow);1991 rc = pHlp->pfnSSMGetMem( pSSM, pVirtq->szName, sizeof(pVirtq->szName));1992 AssertRCReturn(rc, rc);1993 }1994 1995 2260 return VINF_SUCCESS; 1996 2261 } … … 2002 2267 2003 2268 /** 2004 * This must be called by the client to handle VM state changes 2005 * after the client takes care of its device-specific tasks for the state change. 2006 * (i.e. Reset, suspend, power-off, resume) 2269 * This must be called by the client to handle VM state changes after the client takes care of its device-specific 2270 * tasks for the state change (i.e. reset, suspend, power-off, resume) 2007 2271 * 2008 2272 * @param pDevIns The device instance. … … 2057 2321 /** API Function: See header file */ 2058 2322 int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, PVIRTIOPCIPARAMS pPciParams, 2059 const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg) 2323 const char *pcszInstance, uint64_t fDevSpecificFeatures, uint32_t fOfferLegacy, 2324 void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg) 2060 2325 { 2061 2326 /* 2062 * The pVirtio state must be the first member of the shared device instance2063 * data, otherwise we cannot get our bearings in the PCI configurationcallbacks.2327 * Virtio state must be the first member of shared device instance data, 2328 * otherwise can't get our bearings in PCI config callbacks. 2064 2329 */ 2065 2330 AssertLogRelReturn(pVirtio == PDMINS_2_DATA(pDevIns, PVIRTIOCORE), VERR_STATE_CHANGED); … … 2073 2338 AssertReturn(pVirtioCC->pfnStatusChanged, VERR_INVALID_POINTER); 2074 2339 AssertReturn(pVirtioCC->pfnVirtqNotified, VERR_INVALID_POINTER); 2075 AssertReturn(pVirtioCC->pfn GuestVersionHandler, VERR_INVALID_POINTER);2340 AssertReturn(pVirtioCC->pfnFeatureNegotiationComplete, VERR_INVALID_POINTER); 2076 2341 AssertReturn(VIRTQ_SIZE > 0 && VIRTQ_SIZE <= 32768, VERR_OUT_OF_RANGE); /* VirtIO specification-defined limit */ 2077 2342 2078 2343 #if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed 2079 * Thelegacy MSI support has not been implemented yet2344 * VBox legacy MSI support has not been implemented yet 2080 2345 */ 2081 2346 # ifdef VBOX_WITH_MSI_DEVICES … … 2084 2349 #endif 2085 2350 2086 /* Tell the device-specific code that guest is in legacy mode (for now) */2087 pVirtioCC->pfnGuestVersionHandler(pVirtio, false /* fModern */);2088 2089 2351 /* 2090 * The host features offered include both device-specific features2091 * and reserved feature bits (device independent)2352 * Host features (presented as a smörgasbord for guest to select from) 2353 * include both dev-specific features & reserved dev-independent features (bitmask). 2092 2354 */ 2093 2355 pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1 2094 2356 | VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED 2095 2357 | fDevSpecificFeatures; 2358 2359 pVirtio->fLegacyDriver = pVirtio->fOfferLegacy = fOfferLegacy; 2096 2360 2097 2361 RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance); … … 2138 2402 uint32_t cbRegion = 0; 2139 2403 2140 /* Common capability (VirtIO 1.0 spec, section 4.1.4.3) */ 2404 /* 2405 * Common capability (VirtIO 1.0, section 4.1.4.3) 2406 */ 2141 2407 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[0x40]; 2142 2408 pCfg->uCfgType = VIRTIO_PCI_CAP_COMMON_CFG; … … 2152 2418 2153 2419 /* 2154 * Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based on the choice 2155 * of this implementation to make each queue's uNotifyOffset equal to (VirtqSelect) ordinal 2156 * value of the queue (different strategies are possible according to spec). 2420 * Notify capability (VirtIO 1.0, section 4.1.4.4). 2421 * 2422 * The size of the spec-defined subregion described by this VirtIO capability is 2423 * based-on the choice of this implementation to make the notification area of each 2424 * queue equal to queue's ordinal position (e.g. queue selector value). The VirtIO 2425 * specification leaves it up to implementation to define queue notification area layout. 2157 2426 */ 2158 2427 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext]; … … 2170 2439 pVirtioCC->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER; 2171 2440 2172 /* ISR capability (VirtIO 1.0 spec, section 4.1.4.5)2441 /* ISR capability (VirtIO 1.0, section 4.1.4.5) 2173 2442 * 2174 * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram2175 * of spec shows it as a 32-bit field with upper bits 'reserved'2176 * Will take spec's words more literally than the diagram for now.2443 * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. The specification example/diagram 2444 * illustrates this capability as 32-bit field with upper bits 'reserved'. Those depictions 2445 * differ. The spec's wording, not the diagram, is seen to work in practice. 2177 2446 */ 2178 2447 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext]; … … 2189 2458 pVirtioCC->pIsrCap = pCfg; 2190 2459 2191 /* PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7) 2192 * This capability doesn't get page-MMIO mapped. Instead uBar, uOffset and uLength are intercepted 2193 * by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write 2194 * values from any region. NOTE: The linux driver not only doesn't use this feature, it will not 2195 * even list it as present if uLength isn't non-zero and also 4-byte-aligned as the linux driver is 2196 * initializing. 2460 /* PCI Cfg capability (VirtIO 1.0, section 4.1.4.7) 2461 * 2462 * This capability facilitates early-boot access to this device (BIOS). 2463 * This region isn't page-MMIO mapped. PCI configuration accesses are intercepted, 2464 * wherein uBar, uOffset and uLength are modulated by consumers to locate and read/write 2465 * values in any part of any region. (NOTE: Linux driver doesn't utilize this feature. 2466 * This capability only appears in lspci output on Linux if uLength is non-zero, 4-byte aligned, 2467 * during initialization of linux virtio driver). 2197 2468 */ 2198 2469 pVirtio->uPciCfgDataOff = pCfg->uCapNext + RT_OFFSETOF(VIRTIO_PCI_CFG_CAP_T, uPciCfgData); … … 2211 2482 if (pVirtioCC->pbDevSpecificCfg) 2212 2483 { 2213 /* Device specific config capability (via VirtIO 1.0, section 4.1.4.6). 2484 /* Device-specific config capability (VirtIO 1.0, section 4.1.4.6). 2485 * 2214 2486 * Client defines the device-specific config struct and passes size to virtioCoreR3Init() 2215 * to inform this. */ 2487 * to inform this. 2488 */ 2216 2489 pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext]; 2217 2490 pCfg->uCfgType = VIRTIO_PCI_CAP_DEVICE_CFG; … … 2263 2536 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: out of memory allocating string")); /* can we put params in this error? */ 2264 2537 2265 /* As a transitional device that supports legacy VirtIO drivers, this VirtIO device generic implementation presents 2266 * legacy driver interface in I/O space at BAR0. The following maps the common (e.g. device independent) 2267 * dev config area as well as device-specific dev config area (whose size is passed to init function of this VirtIO 2268 * generic device code) for access via Port I/O, since legacy drivers (e.g. pre VirtIO 1.0) don't use MMIO callbacks. 2269 * (See VirtIO 1.1, Section 4.1.4.8). 2270 */ 2271 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, VIRTIO_REGION_LEGACY_IO, sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T) + cbDevSpecificCfg, 2272 virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/, pVirtioCC->pcszPortIoName, 2273 NULL /*paExtDescs*/, &pVirtio->hLegacyIoPorts); 2274 AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register legacy config in I/O space at BAR0 */"))); 2538 if (pVirtio->fOfferLegacy) 2539 { 2540 /* As a transitional device that supports legacy VirtIO drivers, this VirtIO device generic implementation presents 2541 * legacy driver interface in I/O space at BAR0. The following maps the common (e.g. device independent) 2542 * dev config area as well as device-specific dev config area (whose size is passed to init function of this VirtIO 2543 * generic device code) for access via Port I/O, since legacy drivers (e.g. pre VirtIO 1.0) don't use MMIO callbacks. 2544 * (See VirtIO 1.1, Section 4.1.4.8). 2545 */ 2546 rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, VIRTIO_REGION_LEGACY_IO, sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T) + cbDevSpecificCfg, 2547 virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/, pVirtioCC->pcszPortIoName, 2548 NULL /*paExtDescs*/, &pVirtio->hLegacyIoPorts); 2549 AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register legacy config in I/O space at BAR0 */"))); 2550 } 2275 2551 2276 2552 /* Note: The Linux driver at drivers/virtio/virtio_pci_modern.c tries to map at least a page for the 2277 * 'unknown' device-specific capability without querying the capability to figure 2278 * out size, so pad with an extra page 2553 * 'unknown' device-specific capability without querying the capability to determine size, so pad w/extra page. 2279 2554 */ 2280 2555 rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + VIRTIO_PAGE_SIZE, VIRTIO_PAGE_SIZE), … … 2304 2579 # endif /* VBOX_WITH_STATISTICS */ 2305 2580 2306 virtioResetDevice(pDevIns, pVirtio); /* Reset VirtIO specific state of device */2307 2308 2581 return VINF_SUCCESS; 2309 2582 } -
trunk/src/VBox/Devices/VirtIO/VirtioCore.h
r92091 r92939 36 36 # define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) do { } while (0) 37 37 #endif 38 39 /** Marks the start of the virtio saved state (just for sanity). */ 40 #define VIRTIO_SAVEDSTATE_MARKER UINT64_C(0x1133557799bbddff) 38 41 39 42 /** Pointer to the shared VirtIO state. */ … … 57 60 #define VIRTIO_PAGE_SIZE 4096 /**< Page size used by VirtIO specification */ 58 61 59 60 /* Note: The VirtIO specification, particularly rev. 0.95, and clarified in rev 1.0 for transitional devices, 61 says the page sized used for Queue Size calculations is usually 4096 bytes, but dependent on the 62 the transport. In an appendix of the 0.95 spec, the 'mmio device', which has not been 63 implemented by VBox legacy device in VirtualBox, says guest must report the page size. For now 64 will set page size to a static 4096 based on the original VBox legacy VirtIO implementation which 65 tied it to PAGE_SIZE which appears to work (or at least good enough for most practical purposes) */ 66 67 68 /** The following virtioCoreGCPhysChain*() functions mimic the functionality of the related RT s/g functions, 69 * except they work with the data type GCPhys rather than void * 62 /** 63 * @todo Move the following virtioCoreGCPhysChain*() functions mimic the functionality of the related 64 * into some VirtualBox source tree common location and out of this code. 65 * 66 * They behave identically to the S/G utilities in the RT library, except they work with that 67 * GCPhys data type specifically instead of void *, to avoid potentially disastrous mismatch 68 * between sizeof(void *) and sizeof(GCPhys). 69 * 70 70 */ 71 71 typedef struct VIRTIOSGSEG /**< An S/G entry */ … … 91 91 92 92 /** 93 * VirtIO buffers are descriptor chains (scatter-gather vectors). Each buffer is described 94 * by the index of its head descriptor, which in optionally chains to another descriptor 95 * and so on. 96 * 97 * Each descriptor, [len, GCPhys] pair in the chain represents either an OUT segment (e.g. guest-to-host) 98 * or an IN segment (host-to-guest). A VIRTQBUF is created and retured from a call to 99 * virtioCoreR3VirtqAvailBufPeek() or virtioCoreR3VirtqAvailBufGet(). That function consolodates 100 * the VirtIO descriptor chain into a representation, where pSgPhysSend is a GCPhys s/g buffer containing 101 * all of the OUT descriptors and pSgPhysReturn is a GCPhys s/g buffer containing all of IN descriptors 102 * to be filled with data on the host to return to theguest. 93 * VirtIO buffers are descriptor chains (e.g. scatter-gather vectors). A VirtIO buffer is referred to by the index 94 * of its head descriptor. Each descriptor optionally chains to another descriptor, and so on. 95 * 96 * For any given descriptor, each length and GCPhys pair in the chain represents either an OUT segment (e.g. guest-to-host) 97 * or an IN segment (host-to-guest). 98 * 99 * A VIRTQBUF is created and retured from a call to to either virtioCoreR3VirtqAvailBufPeek() or virtioCoreR3VirtqAvailBufGet(). 100 * 101 * Those functions consolidate the VirtIO descriptor chain into a single representation where: 102 * 103 * pSgPhysSend GCPhys s/g buffer containing all of the (VirtIO) OUT descriptors 104 * pSgPhysReturn GCPhys s/g buffer containing all of the (VirtIO) IN descriptors 105 * 106 * The OUT descriptors are data sent from guest to host (dev-specific commands and/or data) 107 * The IN are to be filled with data (converted to physical) on host, to be returned to guest 108 * 103 109 */ 104 110 typedef struct VIRTQBUF … … 166 172 static const VIRTIO_FEATURES_LIST s_aCoreFeatures[] = 167 173 { 174 { VIRTIO_F_VERSION_1, " VERSION_1 Guest driver supports VirtIO specification V1.0+ (e.g. \"modern\")\n" }, 175 { VIRTIO_F_RING_EVENT_IDX, " RING_EVENT_IDX Enables use_event and avail_event fields described in 2.4.7, 2.4.8\n" }, 168 176 { VIRTIO_F_RING_INDIRECT_DESC, " RING_INDIRECT_DESC Driver can use descriptors with VIRTQ_DESC_F_INDIRECT flag set\n" }, 169 { VIRTIO_F_RING_EVENT_IDX, " RING_EVENT_IDX Enables use_event and avail_event fields described in 2.4.7, 2.4.8\n" },170 { VIRTIO_F_VERSION_1, " VERSION Used to detect legacy drivers.\n" },171 177 }; 172 173 178 174 179 #define VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED ( 0 ) /**< TBD: Add VIRTIO_F_INDIRECT_DESC */ … … 202 207 kvirtIoVmStateChangedFor32BitHack = 0x7fffffff 203 208 } VIRTIOVMSTATECHANGED; 204 205 206 209 207 210 /** @def Virtio Device PCI Capabilities type codes */ … … 305 308 typedef struct VIRTQUEUE 306 309 { 307 RTGCPHYS GCPhysVirtqDesc; /**< (MMIO) PhysAdr per-Q desc structsGUEST */308 RTGCPHYS GCPhysVirtqAvail; /**< (MMIO) PhysAdr per-Q avail structsGUEST */309 RTGCPHYS GCPhysVirtqUsed; /**< (MMIO) PhysAdr per-Q used structsGUEST */310 uint16_t uMsixVector; /**< (MMIO) Per-queue vector for MSI-XGUEST */311 uint16_t uEnable; /**< (MMIO) Per-queue enableGUEST */312 uint16_t uNotifyOffset; /**< (MMIO) per-Q notify offsetHOST */313 uint16_t uQueueSize; /**< (MMIO) Per-queue sizeHOST/GUEST */310 RTGCPHYS GCPhysVirtqDesc; /**< (MMIO) Addr of virtq's desc ring GUEST */ 311 RTGCPHYS GCPhysVirtqAvail; /**< (MMIO) Addr of virtq's avail ring GUEST */ 312 RTGCPHYS GCPhysVirtqUsed; /**< (MMIO) Addr of virtq's used ring GUEST */ 313 uint16_t uMsixVector; /**< (MMIO) MSI-X vector GUEST */ 314 uint16_t uEnable; /**< (MMIO) Queue enable flag GUEST */ 315 uint16_t uNotifyOffset; /**< (MMIO) Notification offset for queue HOST */ 316 uint16_t uQueueSize; /**< (MMIO) Size of queue HOST/GUEST */ 314 317 uint16_t uAvailIdxShadow; /**< Consumer's position in avail ring */ 315 318 uint16_t uUsedIdxShadow; /**< Consumer's position in used ring */ … … 317 320 char szName[32]; /**< Dev-specific name of queue */ 318 321 bool fUsedRingEvent; /**< Flags if used idx to notify guest reached */ 319 uint8_t padding[3];322 bool fAttached; /**< Flags if dev-specific client attached */ 320 323 } VIRTQUEUE, *PVIRTQUEUE; 321 324 … … 331 334 uint64_t uDeviceFeatures; /**< (MMIO) Host features offered HOST */ 332 335 uint64_t uDriverFeatures; /**< (MMIO) Host features accepted GUEST */ 336 uint32_t fDriverFeaturesWritten; /**< (MMIO) Host features complete tracking */ 333 337 uint32_t uDeviceFeaturesSelect; /**< (MMIO) hi/lo select uDeviceFeatures GUEST */ 334 338 uint32_t uDriverFeaturesSelect; /**< (MMIO) hi/lo select uDriverFeatures GUEST */ … … 343 347 uint8_t fMsiSupport; /**< Flag set if using MSI instead of ISR */ 344 348 uint16_t uVirtqSelect; /**< (MMIO) queue selector GUEST */ 345 uint32_t fLegacyDriver; /**< Set if guest driver < VirtIO 1.0 */ 349 uint32_t fLegacyDriver; /**< Set if guest drv < VirtIO 1.0 and allowed */ 350 uint32_t fOfferLegacy; /**< Set at init call from dev-specific code */ 346 351 347 352 /** @name The locations of the capability structures in PCI config space and the BAR. … … 354 359 /** @} */ 355 360 356 357 358 361 IOMMMIOHANDLE hMmioPciCap; /**< MMIO handle of PCI cap. region (\#2) */ 359 362 IOMIOPORTHANDLE hLegacyIoPorts; /**< Handle of legacy I/O port range. */ 360 361 363 362 364 #ifdef VBOX_WITH_STATISTICS … … 374 376 STAMPROFILEADV StatWriteRC; /** I/O port and MMIO R3 Write profiling */ 375 377 #endif 376 377 378 378 /** @} */ 379 379 380 } VIRTIOCORE; 380 381 … … 389 390 * @{ */ 390 391 /** 391 * Implementation-specific client callback to report VirtIO version as modern or legacy. 392 * That's the only meaningful distinction in the VirtIO specification. Beyond that 393 * versioning is loosely discernable through feature negotiation. There will be two callbacks, 394 * the first indicates the guest driver is considered legacy VirtIO, as it is critical to 395 * assume that initially. A 2nd callback will occur during feature negotiation 396 * which will indicate the guest is modern, if the guest acknowledges VIRTIO_F_VERSION_1, 397 * feature, or legacy if the feature isn't negotiated. That 2nd callback allows 398 * the device-specific code to configure its behavior in terms of both guest version and features. 392 * Implementation-specific client callback to report VirtIO when feature negotiation is 393 * complete. It should be invoked by the VirtIO core only once. 399 394 * 400 * @param pVirtio Pointer to the shared virtio state. 401 * @param fModern True if guest driver identified itself as modern (e.g. VirtIO 1.0 featured) 395 * @param pVirtio Pointer to the shared virtio state. 396 * @param fDriverFeatures Bitmask of features the guest driver has accepted/declined. 397 * @param fLegacy true if legacy mode offered and until guest driver identifies itself 398 * as modern(e.g. VirtIO 1.0 featured) 402 399 */ 403 DECLCALLBACKMEMBER(void, pfn GuestVersionHandler,(PVIRTIOCORE pVirtio, uint32_t fModern));400 DECLCALLBACKMEMBER(void, pfnFeatureNegotiationComplete, (PVIRTIOCORE pVirtio, uint64_t fDriverFeatures, uint32_t fLegacy)); 404 401 405 402 /** … … 436 433 DECLCALLBACKMEMBER(int, pfnDevCapWrite,(PPDMDEVINS pDevIns, uint32_t offCap, const void *pvBuf, uint32_t cbWrite)); 437 434 438 439 435 /** 440 436 * When guest-to-host queue notifications are enabled, the guest driver notifies the host … … 469 465 { 470 466 /** 471 * When guest-to-host queue notifications are enabled, the guest driver notifies the host 472 * that the avail queue has buffers, and this callback informs the client. 467 * This callback notifies the device-specific portion of this device implementation (if guest-to-host 468 * queue notifications are enabled), that the guest driver has notified the host (this device) 469 * that the VirtIO "avail" ring of a queue has some new s/g buffers added by the guest VirtIO driver. 473 470 * 474 471 * @param pVirtio Pointer to the shared virtio state. … … 488 485 } VIRTIOCORERC; 489 486 490 491 487 /** @typedef VIRTIOCORECC 492 488 * The instance data for the current context. */ 493 489 typedef CTX_SUFF(VIRTIOCORE) VIRTIOCORECC; 494 490 495 496 491 /** @name API for VirtIO parent device 497 492 * @{ */ … … 502 497 * This should be called from PDMDEVREGR3::pfnConstruct. 503 498 * 504 * @param pDevIns The device instance.499 * @param pDevIns Device instance. 505 500 * @param pVirtio Pointer to the shared virtio state. This 506 501 * must be the first member in the shared … … 519 514 int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, 520 515 PVIRTIOPCIPARAMS pPciParams, const char *pcszInstance, 521 uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg); 522 516 uint64_t fDevSpecificFeatures, uint32_t fOfferLegacy, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg); 523 517 /** 524 518 * Initiate orderly reset procedure. This is an exposed API for clients that might need it. … … 532 526 * 'Attaches' host device-specific implementation's queue state to host VirtIO core 533 527 * virtqueue management infrastructure, informing the virtio core of the name of the 534 * queue associated with the queue number. uVirtqNbr is used as the 'handle' for virt queues 535 * in this API (and is opaquely the index into the VirtIO core's array of queue state). 536 * 537 * Virtqueue numbers are VirtIO specification defined (i.e. they are unique within each 538 * VirtIO device type). 528 * queue to associate with the queue number. 529 530 * Note: uVirtqNbr (ordinal index) is used as the 'handle' for virtqs in this VirtioCore 531 * implementation's API (as an opaque selector into the VirtIO core's array of queues' states). 532 * 533 * Virtqueue numbers are actually VirtIO-specification defined device-specifically 534 * (i.e. they are unique within each VirtIO device type), but are in some cases scalable 535 * so only the pattern of queue numbers is defined by the spec and implementations may contain 536 * a self-determined plurality of queues. 539 537 * 540 538 * @param pVirtio Pointer to the shared virtio state. … … 547 545 548 546 /** 549 * Enables or disables a virtq 547 * Detaches host device-specific implementation's queue state from the host VirtIO core 548 * virtqueue management infrastructure, informing the VirtIO core that the queue is 549 * not utilized by the device-specific code. 550 550 * 551 551 * @param pVirtio Pointer to the shared virtio state. 552 552 * @param uVirtqNbr Virtq number 553 * @param fEnable Flags whether to enable or disable the virtq 554 * 555 */ 556 void virtioCoreVirtqEnable(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable); 553 * @param pcszName Name to give queue 554 * 555 * @returns VBox status code. 556 */ 557 int virtioCoreR3VirtqDetach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 558 559 /** 560 * Checks to see whether queue is attached to core. 561 * 562 * @param pVirtio Pointer to the shared virtio state. 563 * @param uVirtqNbr Virtq number 564 * 565 * Returns boolean true or false indicating whether dev-specific reflection 566 * of queue is attached to core. 567 */ 568 bool virtioCoreR3VirtqIsAttached(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 569 570 /** 571 * Checks to see whether queue is enabled. 572 * 573 * @param pVirtio Pointer to the shared virtio state. 574 * @param uVirtqNbr Virtq number 575 * 576 * Returns boolean true or false indicating core queue enable state. 577 * There is no API function to enable the queue, because the actual enabling is handled 578 * by the guest via MMIO. 579 * 580 * NOTE: Guest VirtIO driver's claim over this state is overridden (which violates VirtIO 1.0 spec 581 * in a carefully controlled manner) in the case where the queue MUST be disabled, due to observed 582 * control queue corruption (e.g. null GCPhys virtq base addr) while restoring legacy-only device's 583 * (DevVirtioNet.cpp) as a way to flag that the queue is unusable-as-saved and must to be removed. 584 * That is all handled in the load/save exec logic. Device reset could potentially, depending on 585 * parameters passed from host VirtIO device to guest VirtIO driver, result in guest re-establishing 586 * queue, except, in that situation, the queue operational state would be valid. 587 */ 588 bool virtioCoreR3VirtqIsEnabled(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr); 557 589 558 590 /** 559 591 * Enable or disable notification for the specified queue. 560 592 * 561 * With notification enabled, the guest driver notifies the host device (via MMIO 562 * to the queue notification offset describe in VirtIO 1.0, 4.1.4.4 "Notification Structure Layout") 563 * whenever the guest driver adds a new entry to the avail ring of the respective queue. 564 * 565 * Note: In the VirtIO world, the device sets flags in the used ring to communicate to the driver how to 566 * handle notifications for the avail ring and the drivers sets flags in the avail ring to communicate 567 * to the device how to handle sending interrupts for the used ring. 593 * When queue notifications are enabled, the guest VirtIO driver notifies host VirtIO device 594 * (via MMIO, see VirtIO 1.0, 4.1.4.4 "Notification Structure Layout") whenever guest driver adds 595 * a new s/g buffer to the "avail" ring of the queue. 596 * 597 * Note: VirtIO queue layout includes flags the device controls in "used" ring to inform guest 598 * driver if it should notify host of guest's buffer additions to the "avail" ring, and 599 * conversely, the guest driver sets flags in the "avail" ring to communicate to host device 600 * whether or not to interrupt guest when it adds buffers to used ring. 568 601 * 569 602 * @param pVirtio Pointer to the shared virtio state. … … 581 614 582 615 /** 583 * Displays the VirtIO spec-related features offered and their accepted/declined status 584 * by both the VirtIO core and dev-specific device code (which invokes this function). 585 * The result is a comprehensive list of available features the VirtIO specification 586 * defines, which ones were actually offered by the device, and which ones were accepted 587 * by the guest driver, thus providing a legible summary view of the configuration 588 * the device is operating with. 589 * 616 * Displays a well-formated human-readable translation of otherwise inscrutable bitmasks 617 * that embody features VirtIO specification definitions, indicating: Totality of features 618 * that can be implemented by host and guest, which features were offered by the host, and 619 * which were actually accepted by the guest. It displays it as a summary view of the device's 620 * finalized operational state (host-guest negotiated architecture) in such a way that shows 621 * which options are available for implementing or enabling. 622 * 623 * The non-device-specific VirtIO features list are managed by core API (e.g. implied). 624 * Only dev-specific features must be passed as parameter. 625 590 626 * @param pVirtio Pointer to the shared virtio state. 591 627 * @param pHlp Pointer to the debug info hlp struct 592 * @param s_aDevSpecificFeatures 593 * Features specification lists for device-specific implementation 594 * (i.e: net controller, scsi controller ...) 628 * @param s_aDevSpecificFeatures Dev-specific features (virtio-net, virtio-scsi...) 595 629 * @param cFeatures Number of features in aDevSpecificFeatures 596 630 */ … … 599 633 600 634 /* 601 * Debug ing assist feature displays the state of the VirtIO core code, which includes635 * Debug-assist utility function to display state of the VirtIO core code, including 602 636 * an overview of the state of all of the queues. 603 637 * … … 608 642 * 609 643 * This is implemented currently to be invoked by the inheriting device-specific code 610 * (see DevVirtioNet for an example, which receives the debugvm callback directly). 611 * DevVirtioNet lists the available sub-options if no arguments are provided. In that 644 * (see the the VirtualBox virtio-net (VirtIO network controller device implementation) 645 * for an example of code that receive debugvm callback directly). 646 * 647 * DevVirtioNet lists available sub-options if no arguments are provided. In that 612 648 * example this virtq info related function is invoked hierarchically when virtio-net 613 649 * displays its device-specific queue info. … … 629 665 630 666 /** 631 * This function is identical to virtioCoreR3VirtqAvailBufGet(), except it doesn't 'consume' 632 * the buffer from the avail ring of the virtq. The peek operation becomes identical to a get 633 * operation if virtioCoreR3VirtqAvailRingNext() is called to consume the buffer from the avail ring, 634 * at which point virtioCoreR3VirtqUsedBufPut() must be called to complete the roundtrip 635 * transaction by putting the descriptor on the used ring. 636 * 667 * This function is identical to virtioCoreR3VirtqAvailBufGet(), *except* it doesn't consume 668 * peeked buffer from avail ring of the virtq. The function *becomes* identical to the 669 * virtioCoreR3VirtqAvailBufGet() only if virtioCoreR3VirtqAvailRingNext() is invoked to 670 * consume buf from the queue's avail ring, followed by invocation of virtioCoreR3VirtqUsedBufPut(), 671 * to hand host-processed buffer back to guest, which completes guest-initiated virtq buffer circuit. 637 672 * 638 673 * @param pDevIns The device instance. … … 652 687 /** 653 688 * This function fetches the next buffer (descriptor chain) from the VirtIO "avail" ring of 654 * indicated queue, and convertsthe buf's s/g vectors into OUT (e.g. guest-to-host)689 * indicated queue, separating the buf's s/g vectors into OUT (e.g. guest-to-host) 655 690 * components and and IN (host-to-guest) components. 656 691 * 657 * The caller is responsible for GCPhys to host virtual memory conversions. If the692 * Caller is responsible for GCPhys to host virtual memory conversions. If the 658 693 * virtq buffer being peeked at is "consumed", virtioCoreR3VirtqAvailRingNext() must 659 * be called and in that casevirtioCoreR3VirtqUsedBufPut() must be called to660 * complete the roundtrip virtq transaction.694 * be called, and after that virtioCoreR3VirtqUsedBufPut() must be called to 695 * complete the buffer transfer cycle with the guest. 661 696 * 662 697 * @param pDevIns The device instance. … … 678 713 679 714 /** 680 * Fetches a specific descriptor chain using avail ring of indicated queue and converts the descriptor681 * chain into its OUT (to device) and IN (to guest) components.715 * Fetches a specific descriptor chain using avail ring of indicated queue and converts the 716 * descriptor chain into its OUT (to device) and IN (to guest) components. 682 717 * 683 718 * The caller is responsible for GCPhys to host virtual memory conversions and *must* … … 704 739 /** 705 740 * Returns data to the guest to complete a transaction initiated by virtioCoreR3VirtqAvailBufGet(), 706 * or virtioCoreR3VirtqAvailBufPeek()/virtioCoreR3VirtqBufSync() call pairsto complete each707 * intervening a roundtrip transaction, ultimately putting each descriptor chain pulled from the708 * avail ring of a queue onto the used ring of the queue. wherein I/O transactions are always709 * initiated by the guest and completed by the host. In other words, for the host to send any710 * data to the guest, the guest must provide buffers, for the host to fill, via the avail ring711 * of the virtq.741 * (or virtioCoreR3VirtqAvailBufPeek()/virtioCoreR3VirtqBufSync() call pair), to complete each 742 * buffer transfer transaction (guest-host buffer cycle), ultimately moving each descriptor chain 743 * from the avail ring of a queue onto the used ring of the queue. Note that VirtIO buffer 744 * transactions are *always* initiated by the guest and completed by the host. In other words, 745 * for the host to send any I/O related data to the guest (and in some cases configuration data), 746 * the guest must provide buffers via the virtq's avail ring, for the host to fill. 712 747 * 713 748 * At some some point virtioCoreR3VirtqUsedRingSync() must be called to return data to the guest, 714 * completing all pending virtioCoreR3VirtqAvailBufPut() transactions that have accumulated since 715 * the last call to virtioCoreR3VirtqUsedRingSync() 716 717 * @note This does a write-ahead to the used ring of the guest's queue. The data 718 * written won't be seen by the guest until the next call to virtioCoreVirtqUsedRingSync() 719 * 749 * completing all pending virtioCoreR3VirtqAvailBufPut() operations that have accumulated since 750 * the last call to virtioCoreR3VirtqUsedRingSync(). 751 752 * @note This function effectively performs write-ahead to the used ring of the virtq. 753 * Data written won't be seen by the guest until the next call to virtioCoreVirtqUsedRingSync() 720 754 * 721 755 * @param pDevIns The device instance (for reading). … … 729 763 * buffer originally pulled from the queue. 730 764 * 731 * @param fFence If true , put up copyfence (memory barrier) after765 * @param fFence If true (default), put up copy-fence (memory barrier) after 732 766 * copying to guest phys. mem. 733 767 * … … 741 775 */ 742 776 int virtioCoreR3VirtqUsedBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, PRTSGBUF pSgVirtReturn, 743 PVIRTQBUF pVirtqBuf, bool fFence); 777 PVIRTQBUF pVirtqBuf, bool fFence = true); 778 779 780 /** 781 * Quicker variant of same-named function (directly above) that it overloads, 782 * Instead, this variant accepts as input a pointer to a buffer and count, 783 * instead of S/G buffer thus doesn't have to copy between two S/G buffers and avoids some overhead. 784 * 785 * @param pDevIns The device instance (for reading). 786 * @param pVirtio Pointer to the shared virtio state. 787 * @param uVirtqNbr Virtq number 788 * @param cb Number of bytes to add to copy to phys. buf. 789 * @param pv Virtual mem buf to copy to phys buf. 790 * @param cbEnqueue How many bytes in packet to enqueue (0 = don't enqueue) 791 * @param fFence If true (default), put up copy-fence (memory barrier) after 792 * copying to guest phys. mem. 793 * 794 * @returns VBox status code. 795 * @retval VINF_SUCCESS Success 796 * @retval VERR_INVALID_STATE VirtIO not in ready state 797 * @retval VERR_NOT_AVAILABLE Virtq is empty 798 * 799 * @note This function will not release any reference to pVirtqBuf. The 800 * caller must take care of that. 801 */ 802 int virtioCoreR3VirtqUsedBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq, size_t cb, const void *pv, 803 PVIRTQBUF pVirtqBuf, uint32_t cbEnqueue, bool fFence = true); 804 805 744 806 /** 745 807 * Advance index of avail ring to next entry in specified virtq (see virtioCoreR3VirtqAvailBufPeek()) … … 751 813 752 814 /** 753 * Checks to see if guest has ac knowledged device's VIRTIO_F_VERSION_1 feature.754 * If not, it's presumed to be a VirtIO legacy guest driver. Note that legacy drivers755 * may start using the device prematurely, as opposed to the rigorously sane protocol756 * prescribed by the "modern" VirtIO spec. Early access implies a legacy driver.757 * Therefore legacy mode is the assumption until feature negotiation.815 * Checks to see if guest has accepted host device's VIRTIO_F_VERSION_1 (i.e. "modern") 816 * behavioral modeling, indicating guest agreed to comply with the modern VirtIO 1.0+ specification. 817 * Otherwise unavoidable presumption is that the host device is dealing with legacy VirtIO 818 * guest drive, thus must be prepared to cope with less mature architecture and behaviors 819 * from prototype era of VirtIO. (see comments in PDM-invoked device constructor for more information). 758 820 * 759 821 * @param pVirtio Pointer to the virtio state. … … 761 823 int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio); 762 824 825 /** 826 * This VirtIO transitional device supports "modern" (rev 1.0+) as well as "legacy" (e.g. < 1.0) VirtIO drivers. 827 * Some legacy guest drivers are known to mishandle PCI bus mastering wherein the PCI flavor of GC phys 828 * access functions can't be used. The following wrappers select the memory access method based on whether the 829 * device is operating in legacy mode or not. 830 */ 831 DECLINLINE(int) virtioCoreGCPhysWrite(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbWrite) 832 { 833 int rc; 834 if (virtioCoreIsLegacyMode(pVirtio)) 835 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite); 836 else 837 rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite); 838 return rc; 839 } 840 841 DECLINLINE(int) virtioCoreGCPhysRead(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) 842 { 843 int rc; 844 if (virtioCoreIsLegacyMode(pVirtio)) 845 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBuf, cbRead); 846 else 847 rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead); 848 return rc; 849 } 850 851 /* 852 * (See comments for corresponding function in sg.h) 853 */ 763 854 DECLINLINE(void) virtioCoreGCPhysChainInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs) 764 855 { … … 782 873 } 783 874 875 /* 876 * (See comments for corresponding function in sg.h) 877 */ 784 878 DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainGet(PVIRTIOSGBUF pGcSgBuf, size_t *pcbData) 785 879 { … … 826 920 } 827 921 922 /* 923 * (See comments for corresponding function in sg.h) 924 */ 828 925 DECLINLINE(void) virtioCoreGCPhysChainReset(PVIRTIOSGBUF pGcSgBuf) 829 926 { … … 843 940 } 844 941 942 /* 943 * (See comments for corresponding function in sg.h) 944 */ 845 945 DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainAdvance(PVIRTIOSGBUF pGcSgBuf, size_t cbAdvance) 846 946 { … … 860 960 } 861 961 962 /* 963 * (See comments for corresponding function in sg.h) 964 */ 862 965 DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainGetNextSeg(PVIRTIOSGBUF pGcSgBuf, size_t *pcbSeg) 863 966 { … … 871 974 } 872 975 873 DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PVIRTIOSGBUF pGcSgBuf) 976 /** 977 * Calculate the length of a GCPhys s/g buffer by tallying the size of each segment. 978 * 979 * @param pGcSgBuf Guest Context (GCPhys) S/G buffer to calculate length of 980 */ 981 DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PCVIRTIOSGBUF pGcSgBuf) 874 982 { 875 983 size_t cb = 0; 876 984 unsigned i = pGcSgBuf->cSegs; 877 while (i-- > 0) 878 cb += pGcSgBuf->paSegs[i].cbSeg; 879 return cb; 880 } 881 985 while (i-- > 0) 986 cb += pGcSgBuf->paSegs[i].cbSeg; 987 return cb; 988 } 989 990 /* 991 * (See comments for corresponding function in sg.h) 992 */ 993 DECLINLINE(size_t) virtioCoreGCPhysChainCalcLengthLeft(PVIRTIOSGBUF pGcSgBuf) 994 { 995 size_t cb = pGcSgBuf->cbSegLeft; 996 unsigned i = pGcSgBuf->cSegs; 997 while (i-- > pGcSgBuf->idxSeg + 1) 998 cb += pGcSgBuf->paSegs[i].cbSeg; 999 return cb; 1000 } 882 1001 #define VIRTQNAME(a_pVirtio, a_uVirtq) ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName) 883 1002 884 1003 /** 885 * Add some bytes to a virtq (s/g) buffer, converting them from virtual memory to GCPhys 886 * 887 * To be performant it is left to the caller to validate the size of the buffer with regard 888 * to data being pulled from it to avoid overruns/underruns. 1004 * Convert and append bytes from a virtual-memory simple buffer to VirtIO guest's 1005 * physical memory described by a buffer pulled form the avail ring of a virtq. 889 1006 * 890 1007 * @param pVirtio Pointer to the shared virtio state. 891 * @param pVirtqBuf output: virtq buffer1008 * @param pVirtqBuf VirtIO buffer to fill 892 1009 * @param pv input: virtual memory buffer to receive bytes 893 1010 * @param cb number of bytes to add to the s/g buffer. … … 895 1012 DECLINLINE(void) virtioCoreR3VirqBufFill(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb) 896 1013 { 897 uint8_t *pb = (uint8_t *)pv; 898 size_t cbLim = RT_MIN(pVirtqBuf->cbPhysReturn, cb); 899 while (cbLim) 1014 uint8_t *pvBuf = (uint8_t *)pv; 1015 size_t cbRemain = cb, cbTotal = 0; 1016 PVIRTIOSGBUF pSgPhysReturn = pVirtqBuf->pSgPhysReturn; 1017 while (cbRemain) 900 1018 { 901 size_t cbSeg = cbLim; 902 RTGCPHYS GCPhys = virtioCoreGCPhysChainGetNextSeg(pVirtqBuf->pSgPhysReturn, &cbSeg); 903 PDMDevHlpPCIPhysWrite(pVirtio->pDevInsR3, GCPhys, pb, cbSeg); 904 pb += cbSeg; 905 cbLim -= cbSeg; 906 pVirtqBuf->cbPhysSend -= cbSeg; 1019 uint32_t cbBounded = RT_MIN(pSgPhysReturn->cbSegLeft, cbRemain); 1020 Assert(cbBounded > 0); 1021 virtioCoreGCPhysWrite(pVirtio, CTX_SUFF(pVirtio->pDevIns), (RTGCPHYS)pSgPhysReturn->GCPhysCur, pvBuf, cbBounded); 1022 virtioCoreGCPhysChainAdvance(pSgPhysReturn, cbBounded); 1023 pvBuf += cbBounded; 1024 cbRemain -= cbBounded; 1025 cbTotal += cbBounded; 907 1026 } 908 LogFunc(("Added %d/%d bytes to %s buffer, head idx: %u (%d bytes remain)\n", 909 cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq), 910 pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysReturn)); 911 } 912 913 /** 914 * Extract some bytes out of a virtq (s/g) buffer, converting them from GCPhys to virtual memory 915 * 916 * To be performant it is left to the caller to validate the size of the buffer with regard 917 * to data being pulled from it to avoid overruns/underruns. 1027 LogFunc(("Appended %d bytes to guest phys buf [head: %u]. %d bytes unused in buf.)\n", 1028 cbTotal, pVirtqBuf->uHeadIdx, virtioCoreGCPhysChainCalcLengthLeft(pSgPhysReturn))); 1029 } 1030 1031 /** 1032 * Extract some bytes from of a virtq s/g buffer, converting them from GCPhys space to 1033 * to ordinary virtual memory (i.e. making data directly accessible to host device code) 1034 * 1035 * As a performance optimization, it is left to the caller to validate buffer size. 918 1036 * 919 1037 * @param pVirtio Pointer to the shared virtio state. … … 937 1055 LogFunc(("Drained %d/%d bytes from %s buffer, head idx: %u (%d bytes left)\n", 938 1056 cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq), 939 pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysSend));1057 pVirtqBuf->uHeadIdx, virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn))); 940 1058 } 941 1059 … … 1016 1134 * VirtIO implementation to identify this device's operational configuration after features 1017 1135 * have been negotiated with guest VirtIO driver. Feature negotiation entails host indicating 1018 * to guest which features it supports, then guest accepting among those offeredwhich features1136 * to guest which features it supports, then guest accepting from among the offered, which features 1019 1137 * it will enable. That becomes the agreement between the host and guest. The bitmask containing 1020 1138 * virtio core features plus device-specific features is provided as a parameter to virtioCoreR3Init() … … 1031 1149 1032 1150 /** 1033 * Get the thename of the VM state change associated with the enumeration variable1151 * Get name of the VM state change associated with the enumeration variable 1034 1152 * 1035 1153 * @param enmState VM state (enumeration value) … … 1078 1196 /** 1079 1197 * Debug assist for any consumer device code 1080 &1081 1198 * Do a hex dump of memory in guest physical context 1082 1199 * … … 1093 1210 */ 1094 1211 1095 /**1096 * Calculate the length of a GCPhys s/g buffer by tallying the size of each segment.1097 *1098 * @param pGcSgBuf Guest Context (GCPhys) S/G buffer to calculate length of1099 */1100 DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PCVIRTIOSGBUF pGcSgBuf)1101 {1102 size_t cb = 0;1103 unsigned i = pGcSgBuf->cSegs;1104 while (i-- > 0)1105 cb += pGcSgBuf->paSegs[i].cbSeg;1106 return cb;1107 }1108 1109 /**1110 * This VirtIO transitional device supports "modern" (rev 1.0+) as well as "legacy" (e.g. < 1.0) VirtIO drivers.1111 * Some legacy guest drivers are known to mishandle PCI bus mastering wherein the PCI flavor of GC phys1112 * access functions can't be used. The following wrappers select the mem access method based on whether the1113 * device is operating in legacy mode or not.1114 */1115 DECLINLINE(int) virtioCoreGCPhysWrite(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbWrite)1116 {1117 int rc;1118 if (virtioCoreIsLegacyMode(pVirtio))1119 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);1120 else1121 rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);1122 return rc;1123 }1124 1125 DECLINLINE(int) virtioCoreGCPhysRead(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)1126 {1127 int rc;1128 if (virtioCoreIsLegacyMode(pVirtio))1129 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBuf, cbRead);1130 else1131 rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead);1132 return rc;1133 }1134 1135 1212 /** Misc VM and PDM boilerplate */ 1136 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); 1137 int virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); 1213 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t cQueues); 1214 int virtioCoreR3ModernDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uTestVersion, uint32_t cQueues); 1215 int virtioCoreR3LegacyDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uVirtioLegacy_3_1_Beta); 1138 1216 void virtioCoreR3VmStateChanged(PVIRTIOCORE pVirtio, VIRTIOVMSTATECHANGED enmState); 1139 1217 void virtioCoreR3Term(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC); … … 1147 1225 * cb, pv and fWrite are implicit parameters and must be defined by the invoker. 1148 1226 */ 1149 1150 1227 #ifdef LOG_ENABLED 1151 1228 … … 1201 1278 * the memory described by cb and pv. 1202 1279 * 1203 * cb, pv and fWrite are implicit parameters and must be defined by theinvoker.1280 * cb, pv and fWrite are implicit parameters and must be defined by invoker. 1204 1281 */ 1205 1282 #define VIRTIO_DEV_CONFIG_ACCESS(member, tCfgStruct, uOffsetOfAccess, pCfgStruct) \ … … 1216 1293 /** 1217 1294 * Copies bytes into memory described by cb, pv from the specified member field of the config struct. 1218 * The operation is a nop and logs error if implied parameter fWrite istrue.1295 * The operation is a NOP, logging an error if an implied parameter, fWrite, is boolean true. 1219 1296 * 1220 1297 * cb, pv and fWrite are implicit parameters and must be defined by the invoker. … … 1237 1314 * the memory described by cb and pv. 1238 1315 * 1239 * cb, pv and fWrite are implicit parameters and must be defined by theinvoker.1316 * cb, pv and fWrite are implicit parameters and must be defined by invoker. 1240 1317 */ 1241 1318 #define VIRTIO_DEV_CONFIG_ACCESS_INDEXED(member, uIdx, tCfgStruct, uOffsetOfAccess, pCfgStruct) \ … … 1254 1331 * The operation is a nop and logs error if implied parameter fWrite is true. 1255 1332 * 1256 * cb, pv and fWrite are implicit parameters and must be defined by theinvoker.1333 * cb, pv and fWrite are implicit parameters and must be defined by invoker. 1257 1334 */ 1258 1335 #define VIRTIO_DEV_CONFIG_ACCESS_INDEXED_READONLY(member, uidx, tCfgStruct, uOffsetOfAccess, pCfgStruct) \
Note:
See TracChangeset
for help on using the changeset viewer.