VirtualBox

Changeset 23358 in vbox


Ignore:
Timestamp:
Sep 28, 2009 9:03:12 AM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
52880
Message:

#3987: Virtio: Queues and packet reception/transmission.

Location:
trunk/src/VBox
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevVirtioNet.cpp

    r22866 r23358  
    4343#define INSTANCE(pState) pState->szInstance
    4444#define IFACE_TO_STATE(pIface, ifaceName) ((VPCISTATE *)((char*)pIface - RT_OFFSETOF(VPCISTATE, ifaceName)))
    45 #if 0
    46 /* Little helpers ************************************************************/
    47 #undef htons
    48 #undef ntohs
    49 #undef htonl
    50 #undef ntohl
    51 #define htons(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
    52 #define ntohs(x) htons(x)
    53 #define htonl(x) ASMByteSwapU32(x)
    54 #define ntohl(x) htonl(x)
    55 
    56 #define E1K_RELOCATE(p, o) *(RTHCUINTPTR *)&p += o
    57 
    58 #define E1K_INC_CNT32(cnt) \
    59 do { \
    60     if (cnt < UINT32_MAX) \
    61         cnt++; \
    62 } while (0)
    63 
    64 #define E1K_ADD_CNT64(cntLo, cntHi, val) \
    65 do { \
    66     uint64_t u64Cnt = RT_MAKE_U64(cntLo, cntHi); \
    67     uint64_t tmp  = u64Cnt; \
    68     u64Cnt += val; \
    69     if (tmp > u64Cnt ) \
    70         u64Cnt = UINT64_MAX; \
    71     cntLo = (uint32_t)u64Cnt; \
    72     cntHi = (uint32_t)(u64Cnt >> 32); \
    73 } while (0)
    74 
    75 #ifdef E1K_INT_STATS
    76 # define E1K_INC_ISTAT_CNT(cnt) ++cnt
    77 #else /* E1K_INT_STATS */
    78 # define E1K_INC_ISTAT_CNT(cnt)
    79 #endif /* E1K_INT_STATS */
    80 #endif
     45
     46#define VIRTIO_RELOCATE(p, o) *(RTHCUINTPTR *)&p += o
    8147
    8248/*****************************************************************************/
     
    9056/*****************************************************************************/
    9157
     58//- TODO: Move to Virtio.h ----------------------------------------------------
     59
     60#define VRINGDESC_MAX_SIZE (2 * 1024 * 1024)
     61#define VRINGDESC_F_NEXT   0x01
     62#define VRINGDESC_F_WRITE  0x02
     63
    9264struct VRingDesc
    9365{
     
    9870};
    9971typedef struct VRingDesc VRINGDESC;
     72typedef VRINGDESC *PVRINGDESC;
     73
     74#define VRINGAVAIL_F_NO_NOTIFY 0x01
     75
     76struct VRingAvail
     77{
     78    uint16_t uFlags;
     79    uint16_t uNextFreeIndex;
     80    uint16_t auRing[1];
     81};
     82typedef struct VRingAvail VRINGAVAIL;
     83
     84struct VRingUsedElem
     85{
     86    uint32_t uId;
     87    uint32_t uLen;
     88};
     89typedef struct VRingUsedElem VRINGUSEDELEM;
     90
     91#define VRINGUSED_F_NO_INTERRUPT 0x01
     92
     93struct VRingUsed
     94{
     95    uint16_t      uFlags;
     96    uint16_t      uIndex;
     97    VRINGUSEDELEM aRing[1];
     98};
     99typedef struct VRingUsed VRINGUSED;
     100typedef VRINGUSED *PVRINGUSED;
     101
     102#define VRING_MAX_SIZE 1024
    100103
    101104struct VRing
    102105{
    103106    uint16_t   uSize;
    104     VRINGDESC *pDescriptors;
     107    RTGCPHYS   addrDescriptors;
     108    RTGCPHYS   addrAvail;
     109    RTGCPHYS   addrUsed;
    105110};
    106111typedef struct VRing VRING;
     112typedef VRING *PVRING;
    107113
    108114struct VQueue
    109115{
    110116    VRING    VRing;
     117    uint16_t uNextAvailIndex;
     118    uint16_t uNextUsedIndex;
    111119    uint16_t uPageNumber;
    112120    void   (*pfnCallback)(void *pvState, struct VQueue *pQueue);
     
    115123typedef VQUEUE *PVQUEUE;
    116124
     125struct VQueueElemSeg
     126{
     127    RTGCPHYS addr;
     128    void    *pv;
     129    uint32_t cb;
     130};
     131typedef struct VQueueElemSeg VQUEUESEG;
     132
     133struct VQueueElem
     134{
     135    uint32_t  uIndex;
     136    uint32_t  nIn;
     137    uint32_t  nOut;
     138    VQUEUESEG aSegsIn[VRING_MAX_SIZE];
     139    VQUEUESEG aSegsOut[VRING_MAX_SIZE];
     140};
     141typedef struct VQueueElem VQUEUEELEM;
     142typedef VQUEUEELEM *PVQUEUEELEM;
     143
     144
    117145enum VirtioDeviceType
    118146{
     
    123151struct VPCIState_st
    124152{
     153    PDMCRITSECT cs;                  /**< Critical section - what is it protecting? */
    125154    /* Read-only part, never changes after initialization. */
    126155    VirtioDeviceType        enmDevType;               /**< Device type: net or blk. */
     
    141170
    142171    /* Read/write part, protected with critical section. */
    143     PDMCRITSECT cs;                  /**< Critical section - what is it protecting? */
    144172    /** Status LED. */
    145173    PDMLED      led;
     
    160188};
    161189typedef struct VPCIState_st VPCISTATE;
     190typedef VPCISTATE *PVPCISTATE;
     191
     192//- TODO: Move to VirtioPCI.cpp -----------------------------------------------
    162193
    163194struct VirtioPCIDevices
     
    199230#define VPCI_CONFIG         0x14
    200231
     232#define VPCI_STATUS_ACK     0x01
     233#define VPCI_STATUS_DRV     0x02
     234#define VPCI_STATUS_DRV_OK  0x04
     235#define VPCI_STATUS_FAILED  0x80
     236
    201237/** @todo use+extend RTNETIPV4 */
    202238
    203239/** @todo use+extend RTNETTCP */
    204 
    205 #define VNET_SAVEDSTATE_VERSION 1
    206240
    207241#ifndef VBOX_DEVICE_STRUCT_TESTCASE
     
    211245PDMBOTHCBDECL(int) vpciIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
    212246PDMBOTHCBDECL(int) vpciIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
     247PDMBOTHCBDECL(int) vpciRaiseInterrupt(VPCISTATE *pState, int rcBusy, uint8_t u8IntCause);
    213248RT_C_DECLS_END
     249
     250
     251static void vqueueInit(PVQUEUE pQueue, uint32_t uPageNumber)
     252{
     253    pQueue->VRing.addrDescriptors = uPageNumber << PAGE_SHIFT;
     254    pQueue->VRing.addrAvail       = pQueue->VRing.addrDescriptors
     255        + sizeof(VRINGDESC) * pQueue->VRing.uSize;
     256    pQueue->VRing.addrUsed        = RT_ALIGN(
     257        pQueue->VRing.addrAvail + RT_OFFSETOF(VRINGAVAIL, auRing[pQueue->VRing.uSize]),
     258        PAGE_SIZE); /* The used ring must start from the next page. */
     259    pQueue->uNextAvailIndex       = 0;
     260    pQueue->uNextUsedIndex        = 0;
     261}
     262
     263uint16_t vringReadAvailIndex(PVPCISTATE pState, PVRING pVRing)
     264{
     265    uint16_t tmp;
     266   
     267    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
     268                      pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, uNextFreeIndex),
     269                      &tmp, sizeof(tmp));
     270    return tmp;
     271}
     272
     273DECLINLINE(bool) vqueueIsReady(PVPCISTATE pState, PVQUEUE pQueue)
     274{
     275    return !!pQueue->VRing.addrAvail;
     276}
     277
     278DECLINLINE(bool) vqueueIsEmpty(PVPCISTATE pState, PVQUEUE pQueue)
     279{
     280    return (vringReadAvailIndex(pState, &pQueue->VRing) == pQueue->uNextAvailIndex);
     281}
     282
     283void vqueueElemFree(PVQUEUEELEM pElem)
     284{
     285}
     286
     287void vringReadDesc(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex, PVRINGDESC pDesc)
     288{
     289    Log(("%s vringReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVRing, uIndex));
     290    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
     291                      pVRing->addrDescriptors + sizeof(VRINGDESC) * (uIndex % pVRing->uSize),
     292                      pDesc, sizeof(VRINGDESC));
     293}
     294
     295static uint16_t vringReadAvail(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex)
     296{
     297    uint16_t tmp;
     298   
     299    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
     300                      pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, auRing[uIndex]),
     301                      &tmp, sizeof(tmp));
     302    return tmp;
     303}
     304
     305bool vqueueGet(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem)
     306{
     307    if (vqueueIsEmpty(pState, pQueue))
     308        return false;
     309   
     310    pElem->nIn = pElem->nOut = 0;
     311
     312    Log2(("%s vqueueGet: avail_idx=%u\n", INSTANCE(pState), pQueue->uNextAvailIndex));
     313
     314    VRINGDESC desc;
     315    uint16_t  idx = vringReadAvail(pState, &pQueue->VRing, pQueue->uNextAvailIndex++);
     316    pElem->uIndex = idx;
     317    do
     318    {
     319        VQUEUESEG *pSeg;
     320
     321        vringReadDesc(pState, &pQueue->VRing, idx, &desc);
     322        if (desc.u16Flags & VRINGDESC_F_WRITE)
     323        {
     324            Log2(("%s vqueueGet: IN  idx=%u seg=%u addr=%p cb=%u\n", INSTANCE(pState), idx,
     325                  idx, desc.u64Addr, desc.uLen));
     326            pSeg = &pElem->aSegsIn[pElem->nIn++];
     327        }
     328        else
     329        {
     330            Log2(("%s vqueueGet: OUT idx=%u seg=%u addr=%p cb=%u\n", INSTANCE(pState), idx,
     331                  idx, desc.u64Addr, desc.uLen));
     332            pSeg = &pElem->aSegsOut[pElem->nOut++];
     333        }
     334
     335        pSeg->addr = desc.u64Addr;
     336        pSeg->cb   = desc.uLen;
     337        pSeg->pv   = NULL;
     338
     339        idx = desc.u16Next;
     340    } while (desc.u16Flags & VRINGDESC_F_NEXT);
     341
     342    Log2(("%s vqueueGet: idx=%u nIn=%u nOut=%u\n", INSTANCE(pState),
     343          pElem->uIndex, pElem->nIn, pElem->nOut));
     344    return true;
     345}
     346
     347uint16_t vringReadUsedIndex(PVPCISTATE pState, PVRING pVRing)
     348{
     349    uint16_t tmp;
     350    PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
     351                      pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uIndex),
     352                      &tmp, sizeof(tmp));
     353    return tmp;
     354}
     355
     356void vringWriteUsedIndex(PVPCISTATE pState, PVRING pVRing, uint16_t u16Value)
     357{
     358    PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
     359                       pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uIndex),
     360                       &u16Value, sizeof(u16Value));
     361}
     362
     363void vringWriteUsedElem(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex, uint32_t uId, uint32_t uLen)
     364{
     365    VRINGUSEDELEM elem;
     366
     367    elem.uId = uId;
     368    elem.uLen = uLen;
     369    PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
     370                       pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, aRing[uIndex]),
     371                       &elem, sizeof(elem));
     372}
     373
     374void vqueuePut(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen)
     375{
     376    unsigned int i, uOffset;
     377
     378    Log2(("%s vqueuePut: idx=%u acb=%u\n", INSTANCE(pState), pElem->uIndex, uLen));
     379    for (i = uOffset = 0; i < pElem->nIn && uOffset < uLen; i++)
     380    {
     381        uint32_t cbSegLen = RT_MIN(uLen - uOffset, pElem->aSegsIn[i].cb);
     382        if (pElem->aSegsIn[i].pv)
     383        {
     384            Log2(("%s vqueuePut: used_idx=%u idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", INSTANCE(pState),
     385                  pQueue->uNextUsedIndex, pElem->uIndex, i, pElem->aSegsIn[i].addr, pElem->aSegsIn[i].pv, pElem->aSegsIn[i].cb, cbSegLen));
     386            PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns), pElem->aSegsIn[i].addr,
     387                               pElem->aSegsIn[i].pv, cbSegLen);
     388        }
     389        uOffset += cbSegLen;
     390    }
     391
     392    vringWriteUsedElem(pState, &pQueue->VRing, pQueue->uNextUsedIndex, pElem->uIndex, uLen);
     393    pQueue->uNextUsedIndex = (pQueue->uNextUsedIndex + 1) % pQueue->VRing.uSize;
     394}
     395
     396void vqueueNotify(PVPCISTATE pState, PVQUEUE pQueue)
     397{
     398    int rc = vpciRaiseInterrupt(pState, VERR_INTERNAL_ERROR, VPCI_ISR_QUEUE);
     399    if (RT_FAILURE(rc))
     400        Log(("%s vqueueNotify: Failed to raise an interrupt (%Vrc).\n", INSTANCE(pState), rc));
     401}
     402
     403void vqueueSync(PVPCISTATE pState, PVQUEUE pQueue)
     404{
     405    Log2(("%s vqueueSync: used_idx=%u\n", INSTANCE(pState), pQueue->uNextUsedIndex));
     406    vringWriteUsedIndex(pState, &pQueue->VRing, pQueue->uNextUsedIndex);
     407    vqueueNotify(pState, pQueue);
     408}
    214409
    215410/**
     
    323518            *(uint8_t*)pu32 = pState->uISR;
    324519            pState->uISR = 0; /* read clears all interrupts */
     520            vpciLowerInterrupt(pState);
    325521            break;
    326522
     
    379575             */
    380576            pState->pQueues[pState->uQueueSelector].uPageNumber = u32;
    381             pState->pQueues[pState->uQueueSelector].VRing.pDescriptors = (VRINGDESC*)(u32 << PAGE_SHIFT);
     577            if (u32)
     578                vqueueInit(&pState->pQueues[pState->uQueueSelector], u32);
     579            else
     580                g_VPCIDevices[pState->enmDevType].pfnReset(pState);
    382581            break;
    383582
     
    392591
    393592        case VPCI_QUEUE_NOTIFY:
    394             // TODO
     593            Assert(cb == 2);
     594            u32 &= 0xFFFF;
     595            if (u32 < g_VPCIDevices[pState->enmDevType].nQueues)
     596                if (pState->pQueues[u32].VRing.addrDescriptors)
     597                    pState->pQueues[u32].pfnCallback(pState, &pState->pQueues[u32]);
     598                else
     599                    Log(("%s The queue (#%d) being notified has not been initialized.\n",
     600                         INSTANCE(pState), u32));
     601            else
     602                Log(("%s Invalid queue number (%d)\n", INSTANCE(pState), u32));
    395603            break;
    396604
     
    511719 * @thread  EMT
    512720 */
    513 DECLINLINE(void) virtioPCICfgSetU8(PCIDEVICE& refPciDev, uint32_t uOffset, uint8_t u8Value)
     721DECLINLINE(void) vpciCfgSetU8(PCIDEVICE& refPciDev, uint32_t uOffset, uint8_t u8Value)
    514722{
    515723    Assert(uOffset < sizeof(refPciDev.config));
     
    524732 * @thread  EMT
    525733 */
    526 DECLINLINE(void) virtioPCICfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t u16Value)
     734DECLINLINE(void) vpciCfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t u16Value)
    527735{
    528736    Assert(uOffset+sizeof(u16Value) <= sizeof(refPciDev.config));
     
    537745 * @thread  EMT
    538746 */
    539 DECLINLINE(void) virtioPCICfgSetU32(PCIDEVICE& refPciDev, uint32_t uOffset, uint32_t u32Value)
     747DECLINLINE(void) vpciCfgSetU32(PCIDEVICE& refPciDev, uint32_t uOffset, uint32_t u32Value)
    540748{
    541749    Assert(uOffset+sizeof(u32Value) <= sizeof(refPciDev.config));
     
    556764    PCIDevSetVendorId(&pci, g_VPCIDevices[enmType].uPCIVendorId);
    557765    PCIDevSetDeviceId(&pci, g_VPCIDevices[enmType].uPCIDeviceId);
    558     virtioPCICfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_VPCIDevices[enmType].uPCISubsystemVendorId);
    559     virtioPCICfgSetU16(pci, VBOX_PCI_SUBSYSTEM_ID, g_VPCIDevices[enmType].uPCISubsystemId);
     766    vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_VPCIDevices[enmType].uPCISubsystemVendorId);
     767    vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_ID, g_VPCIDevices[enmType].uPCISubsystemId);
    560768
    561769    /* ABI version, must be equal 0 as of 2.6.30 kernel. */
    562     virtioPCICfgSetU8( pci, VBOX_PCI_REVISION_ID,          0x00);
     770    vpciCfgSetU8( pci, VBOX_PCI_REVISION_ID,          0x00);
    563771    /* Ethernet adapter */
    564     virtioPCICfgSetU8( pci, VBOX_PCI_CLASS_PROG,           0x00);
    565     virtioPCICfgSetU16(pci, VBOX_PCI_CLASS_DEVICE, g_VPCIDevices[enmType].uPCIClass);
     772    vpciCfgSetU8( pci, VBOX_PCI_CLASS_PROG,           0x00);
     773    vpciCfgSetU16(pci, VBOX_PCI_CLASS_DEVICE, g_VPCIDevices[enmType].uPCIClass);
    566774    /* Interrupt Pin: INTA# */
    567     virtioPCICfgSetU8( pci, VBOX_PCI_INTERRUPT_PIN,        0x01);
     775    vpciCfgSetU8( pci, VBOX_PCI_INTERRUPT_PIN,        0x01);
    568776}
    569777
     
    690898    {
    691899        pQueue->VRing.uSize = uSize;
    692         pQueue->VRing.pDescriptors = NULL;
     900        pQueue->VRing.addrDescriptors = 0;
    693901        pQueue->uPageNumber = 0;
    694902        pQueue->pfnCallback = pfnCallback;
     
    698906}
    699907
     908
    700909#endif /* IN_RING3 */
    701910
     
    703912//------------------------- Tear off here: vnet -------------------------------
    704913
     914//- TODO: Move to VirtioNet.h -------------------------------------------------
     915
     916#define VNET_MAX_FRAME_SIZE     65536  // TODO: Is it the right limit?
     917#define VNET_SAVEDSTATE_VERSION 1
     918
    705919/* Virtio net features */
    706 #define NET_F_CSUM       0x00000001  /* Host handles pkts w/ partial csum */
    707 #define NET_F_GUEST_CSUM 0x00000002  /* Guest handles pkts w/ partial csum */
    708 #define NET_F_MAC        0x00000020  /* Host has given MAC address. */
    709 #define NET_F_GSO        0x00000040  /* Host handles pkts w/ any GSO type */
    710 #define NET_F_GUEST_TSO4 0x00000080  /* Guest can handle TSOv4 in. */
    711 #define NET_F_GUEST_TSO6 0x00000100  /* Guest can handle TSOv6 in. */
    712 #define NET_F_GUEST_ECN  0x00000200  /* Guest can handle TSO[6] w/ ECN in. */
    713 #define NET_F_GUEST_UFO  0x00000400  /* Guest can handle UFO in. */
    714 #define NET_F_HOST_TSO4  0x00000800  /* Host can handle TSOv4 in. */
    715 #define NET_F_HOST_TSO6  0x00001000  /* Host can handle TSOv6 in. */
    716 #define NET_F_HOST_ECN   0x00002000  /* Host can handle TSO[6] w/ ECN in. */
    717 #define NET_F_HOST_UFO   0x00004000  /* Host can handle UFO in. */
    718 #define NET_F_MRG_RXBUF  0x00008000  /* Host can merge receive buffers. */
    719 #define NET_F_STATUS     0x00010000  /* virtio_net_config.status available */
    720 #define NET_F_CTRL_VQ    0x00020000  /* Control channel available */
    721 #define NET_F_CTRL_RX    0x00040000  /* Control channel RX mode support */
    722 #define NET_F_CTRL_VLAN  0x00080000  /* Control channel VLAN filtering */
    723 
    724 #define NET_S_LINK_UP    1
     920#define VNET_F_CSUM       0x00000001  /* Host handles pkts w/ partial csum */
     921#define VNET_F_GUEST_CSUM 0x00000002  /* Guest handles pkts w/ partial csum */
     922#define VNET_F_MAC        0x00000020  /* Host has given MAC address. */
     923#define VNET_F_GSO        0x00000040  /* Host handles pkts w/ any GSO type */
     924#define VNET_F_GUEST_TSO4 0x00000080  /* Guest can handle TSOv4 in. */
     925#define VNET_F_GUEST_TSO6 0x00000100  /* Guest can handle TSOv6 in. */
     926#define VNET_F_GUEST_ECN  0x00000200  /* Guest can handle TSO[6] w/ ECN in. */
     927#define VNET_F_GUEST_UFO  0x00000400  /* Guest can handle UFO in. */
     928#define VNET_F_HOST_TSO4  0x00000800  /* Host can handle TSOv4 in. */
     929#define VNET_F_HOST_TSO6  0x00001000  /* Host can handle TSOv6 in. */
     930#define VNET_F_HOST_ECN   0x00002000  /* Host can handle TSO[6] w/ ECN in. */
     931#define VNET_F_HOST_UFO   0x00004000  /* Host can handle UFO in. */
     932#define VNET_F_MRG_RXBUF  0x00008000  /* Host can merge receive buffers. */
     933#define VNET_F_STATUS     0x00010000  /* virtio_net_config.status available */
     934#define VNET_F_CTRL_VQ    0x00020000  /* Control channel available */
     935#define VNET_F_CTRL_RX    0x00040000  /* Control channel RX mode support */
     936#define VNET_F_CTRL_VLAN  0x00080000  /* Control channel VLAN filtering */
     937
     938#define VNET_S_LINK_UP    1
    725939
    726940
     
    7921006};
    7931007typedef struct VNetState_st VNETSTATE;
     1008typedef VNETSTATE *PVNETSTATE;
     1009
     1010#define VNETHDR_GSO_NONE 0
     1011
     1012struct VNetHdr
     1013{
     1014    uint8_t u8Flags;
     1015    uint8_t u8GSOType;
     1016    uint16_t u16HdrLen;
     1017    uint16_t u16GSOSize;
     1018    uint16_t u16CSumStart;
     1019    uint16_t u16CSumOffset;
     1020};
     1021typedef struct VNetHdr VNETHDR;
     1022typedef VNETHDR *PVNETHDR;
    7941023
    7951024AssertCompileMemberOffset(VNETSTATE, VPCI, 0);
     1025
     1026//- TODO: Leave here ----------------------------------------------------------
    7961027
    7971028#undef INSTANCE
     
    8041035{
    8051036    // TODO: implement
    806     return NET_F_MAC | NET_F_STATUS;
     1037    return VNET_F_MAC | VNET_F_STATUS;
    8071038}
    8081039
     
    8711102    VNETSTATE *pState = (VNETSTATE *)pvUser;
    8721103
    873     STATUS |= NET_S_LINK_UP;
     1104    STATUS |= VNET_S_LINK_UP;
    8741105    vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
    8751106}
     
    8961127 * This must be called before the pfnRecieve() method is called.
    8971128 *
    898  * @returns Number of bytes the device can receive.
     1129 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
    8991130 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
    9001131 * @thread  EMT
     
    9021133static int vnetCanReceive(VNETSTATE *pState)
    9031134{
    904     size_t cb;
    905 
    906     cb = 0; // TODO
    907     return cb > 0 ? VINF_SUCCESS : VERR_NET_NO_BUFFER_SPACE;
     1135    return (vqueueIsReady(&pState->VPCI, pState->pRxQueue)
     1136            && !vqueueIsEmpty(&pState->VPCI, pState->pRxQueue))
     1137        ? VINF_SUCCESS : VERR_NET_NO_BUFFER_SPACE;
    9081138}
    9091139
     
    9641194
    9651195/**
     1196 * Determines if the packet is to be delivered to upper layer. The following
     1197 * filters supported:
     1198 * - Exact Unicast/Multicast
     1199 * - Promiscuous Unicast/Multicast
     1200 * - Multicast
     1201 * - VLAN
     1202 *
     1203 * @returns true if packet is intended for this node.
     1204 * @param   pState          Pointer to the state structure.
     1205 * @param   pvBuf           The ethernet packet.
     1206 * @param   cb              Number of bytes available in the packet.
     1207 */
     1208static bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
     1209{
     1210    return true; // TODO: Implement!
     1211}
     1212
     1213/**
     1214 * Pad and store received packet.
     1215 *
     1216 * @remarks Make sure that the packet appears to upper layer as one coming
     1217 *          from real Ethernet: pad it and insert FCS.
     1218 *
     1219 * @returns VBox status code.
     1220 * @param   pState          The device state structure.
     1221 * @param   pvBuf           The available data.
     1222 * @param   cb              Number of bytes available in the buffer.
     1223 */
     1224static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
     1225{
     1226    VNETHDR hdr;
     1227    memset(&hdr, 0, sizeof(hdr));
     1228    /*hdr.u8Flags   = 0;
     1229      hdr.u8GSOType = VNETHDR_GSO_NONE;*/
     1230
     1231    unsigned int uOffset = 0;
     1232    for (unsigned int nElem = 0; uOffset < cb; nElem++)
     1233    {
     1234        VQUEUEELEM elem;
     1235        unsigned int nSeg = 0, uElemSize = 0;
     1236
     1237        if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
     1238        {
     1239            Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
     1240            return VERR_INTERNAL_ERROR;
     1241        }
     1242
     1243        if (elem.nIn < 1)
     1244        {
     1245            Log(("%s vnetHandleRxPacket: No writable descriptors in receive queue!\n", INSTANCE(pState)));
     1246            return VERR_INTERNAL_ERROR;
     1247        }
     1248
     1249        if (nElem == 0)
     1250        {
     1251            /* The very first segment of the very first element gets the header. */
     1252            if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
     1253            {
     1254                Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
     1255                return VERR_INTERNAL_ERROR;
     1256            }
     1257
     1258            elem.aSegsIn[nSeg++].pv = &hdr;
     1259            uElemSize += sizeof(VNETHDR);
     1260        }
     1261
     1262        while (nSeg < elem.nIn && uOffset < cb)
     1263        {
     1264            unsigned int uSize = RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
     1265            elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
     1266            uOffset += uSize;
     1267            uElemSize += uSize;
     1268        }
     1269        elem.uIndex = nElem;
     1270        vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
     1271    }
     1272    vqueueSync(&pState->VPCI, pState->pRxQueue);
     1273   
     1274    return VINF_SUCCESS;
     1275}
     1276
     1277/**
    9661278 * Receive data from the network.
    9671279 *
     
    9761288    VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
    9771289    int        rc = VINF_SUCCESS;
    978     // TODO: Implement
     1290 
     1291    Log2(("%s vnetReceive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
     1292    rc = vnetCanReceive(pState);
     1293    if (RT_FAILURE(rc))
     1294        return rc;
     1295
     1296    if (vnetAddressFilter(pState, pvBuf, cb))
     1297        rc = vnetHandleRxPacket(pState, pvBuf, cb);
     1298
    9791299    return rc;
    9801300}
     
    10051325{
    10061326    VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
    1007     if (STATUS & NET_S_LINK_UP)
     1327    if (STATUS & VNET_S_LINK_UP)
    10081328        return PDMNETWORKLINKSTATE_UP;
    10091329    return PDMNETWORKLINKSTATE_DOWN;
     
    10211341{
    10221342    VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
    1023     bool fOldUp = !!(STATUS & NET_S_LINK_UP);
     1343    bool fOldUp = !!(STATUS & VNET_S_LINK_UP);
    10241344    bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
    10251345
     
    10291349        {
    10301350            Log(("%s Link is up\n", INSTANCE(pState)));
    1031             STATUS |= NET_S_LINK_UP;
     1351            STATUS |= VNET_S_LINK_UP;
    10321352            vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
    10331353        }
     
    10351355        {
    10361356            Log(("%s Link is down\n", INSTANCE(pState)));
    1037             STATUS &= ~NET_S_LINK_UP;
     1357            STATUS &= ~VNET_S_LINK_UP;
    10381358            vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
    10391359        }
     
    10441364}
    10451365
    1046 static DECLCALLBACK(void) vnetReceive(void *pvState, PVQUEUE pQueue)
     1366static DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
    10471367{
    10481368    VNETSTATE *pState = (VNETSTATE*)pvState;
    1049 }
    1050 
    1051 static DECLCALLBACK(void) vnetTransmit(void *pvState, PVQUEUE pQueue)
     1369    Log(("%s Receive buffers has been added.\n", INSTANCE(pState)));
     1370}
     1371
     1372static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
    10521373{
    10531374    VNETSTATE *pState = (VNETSTATE*)pvState;
    1054 }
    1055 
    1056 static DECLCALLBACK(void) vnetControl(void *pvState, PVQUEUE pQueue)
     1375    if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
     1376    {
     1377        Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
     1378             INSTANCE(pState), pState->VPCI.uStatus));
     1379        return;
     1380    }
     1381
     1382    VQUEUEELEM elem;
     1383    while (vqueueGet(&pState->VPCI, pQueue, &elem))
     1384    {
     1385        unsigned int uOffset = 0;
     1386        if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
     1387        {
     1388            Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
     1389                 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
     1390            vqueueElemFree(&elem);
     1391            break; /* For now we simply ignore the header, but it must be there anyway! */
     1392        }
     1393        else
     1394        {
     1395            uint8_t *pFrame = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
     1396            if (!pFrame)
     1397            {
     1398                Log(("%s vnetQueueTransmit: Failed to allocate %u bytes.\n",
     1399                     INSTANCE(pState), VNET_MAX_FRAME_SIZE));
     1400                vqueueElemFree(&elem);
     1401                break; /* For now we simply ignore the header, but it must be there anyway! */
     1402            }
     1403
     1404            /* Assemble a complete frame. */
     1405            for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
     1406            {
     1407                unsigned int uSize = elem.aSegsOut[i].cb;
     1408                if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
     1409                {
     1410                    Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
     1411                    uSize = VNET_MAX_FRAME_SIZE - uOffset;
     1412                }
     1413                PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
     1414                                  pFrame + uOffset, uSize);
     1415                uOffset += uSize;
     1416            }
     1417            STAM_PROFILE_ADV_START(&pState->StatTransmitSend, a);
     1418            int rc = pState->pDrv->pfnSend(pState->pDrv, pFrame, uOffset);
     1419            STAM_PROFILE_ADV_STOP(&pState->StatTransmitSend, a);
     1420            RTMemFree(pFrame);
     1421        }
     1422        vqueuePut(&pState->VPCI, pQueue, &elem, uOffset);
     1423        vqueueSync(&pState->VPCI, pQueue);
     1424    }
     1425}
     1426
     1427static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
    10571428{
    10581429    VNETSTATE *pState = (VNETSTATE*)pvState;
     1430    Log(("%s Pending control message\n", INSTANCE(pState)));
    10591431}
    10601432
     
    10821454    pState->VPCI.IBase.pfnQueryInterface     = vnetQueryInterface;
    10831455    rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance, VIRTIO_NET_ID, sizeof(VNetPCIConfig));
    1084     pState->pRxQueue  = vpciAddQueue(&pState->VPCI, 256, vnetReceive);
    1085     pState->pTxQueue  = vpciAddQueue(&pState->VPCI, 256, vnetTransmit);
    1086     pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16,  vnetControl);
     1456    pState->pRxQueue  = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive);
     1457    pState->pTxQueue  = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit);
     1458    pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16,  vnetQueueControl);
    10871459
    10881460    Log(("%s Constructing new instance\n", INSTANCE(pState)));
     
    11221494    // TODO:
    11231495    /*
    1124     rc = PDMDevHlpSSMRegisterEx(pDevIns, VNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
     1496    rc = PDMDevHlpSSMRegisterEx(pDevIns, VVNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
    11251497                                NULL, NULL, NULL,
    11261498                                NULL, vnetSaveExec, NULL,
     
    13261698     * network card
    13271699     */
    1328     if ((STATUS & NET_S_LINK_UP) && RT_SUCCESS(rc))
    1329     {
    1330         STATUS &= ~NET_S_LINK_UP;
     1700    if ((STATUS & VNET_S_LINK_UP) && RT_SUCCESS(rc))
     1701    {
     1702        STATUS &= ~VNET_S_LINK_UP;
    13311703        vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
    13321704        /* Restore the link back in 5 seconds. */
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r23333 r23358  
    191191else ifdef VBOX_GUI_USE_QGL
    192192 VirtualBox_DEFS        += VBOX_GUI_USE_QGL
     193endif
     194ifdef VBOX_WITH_VIRTIO
     195 VirtualBox_DEFS        += VBOX_WITH_VIRTIO
    193196endif
    194197
  • trunk/src/VBox/Frontends/VirtualBox/src/VBoxGlobal.cpp

    r23223 r23358  
    26652665    mNetworkAdapterTypes [KNetworkAdapterType_I82545EM] =
    26662666        tr ("Intel PRO/1000 MT Server (82545EM)", "NetworkAdapterType");
     2667#ifdef VBOX_WITH_VIRTIO
     2668    mNetworkAdapterTypes [KNetworkAdapterType_Virtio] =
     2669        tr ("Virtio Network Adapter", "NetworkAdapterType");
     2670#endif /* VBOX_WITH_VIRTIO */
    26672671
    26682672    mNetworkAttachmentTypes [KNetworkAttachmentType_Null] =
Note: See TracChangeset for help on using the changeset viewer.

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