VirtualBox

Changeset 24834 in vbox for trunk


Ignore:
Timestamp:
Nov 20, 2009 8:51:12 PM (15 years ago)
Author:
vboxsync
Message:

#3987: Virtio: Split DevVirtioNet.cpp into three files.

Location:
trunk
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/log.h

    r22866 r24834  
    138138    /** VGA Device group. */
    139139    LOG_GROUP_DEV_VGA,
     140    /** Virtio PCI Device group. */
     141    LOG_GROUP_DEV_VIRTIO,
    140142    /** Virtio Network Device group. */
    141143    LOG_GROUP_DEV_VIRTIO_NET,
     
    388390    "DEV_USB",      \
    389391    "DEV_VGA",      \
     392    "DEV_VIRTIO",   \
    390393    "DEV_VIRTIO_NET", \
    391394    "DEV_VMM",      \
  • trunk/src/VBox/Devices/Makefile.kmk

    r24706 r24834  
    318318 DevicesR3_DEFS        += VBOX_WITH_VIRTIO
    319319 DevicesR3_SOURCES     += \
     320        Virtio.cpp \
    320321        Network/DevVirtioNet.cpp
    321322endif
     
    515516 VBoxDDGC_DEFS         += VBOX_WITH_VIRTIO
    516517 VBoxDDGC_SOURCES      += \
     518        Virtio.cpp \
    517519        Network/DevVirtioNet.cpp
    518520endif
     
    612614 VBoxDDR0_DEFS         += VBOX_WITH_VIRTIO
    613615 VBoxDDR0_SOURCES      += \
     616        Virtio.cpp \
    614617        Network/DevVirtioNet.cpp
    615618endif
  • trunk/src/VBox/Devices/Network/DevVirtioNet.cpp

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

    r24757 r24834  
    13361336#ifdef VBOX_WITH_VIRTIO
    13371337    GEN_CHECK_OFF(VPCISTATE, cs);
    1338     GEN_CHECK_OFF(VPCISTATE, enmDevType);
    13391338    GEN_CHECK_OFF(VPCISTATE, szInstance);
    13401339    GEN_CHECK_OFF(VPCISTATE, IBase);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette