VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevVirtioNet.cpp@ 24074

Last change on this file since 24074 was 23979, checked in by vboxsync, 15 years ago

#3987: Virtio: Fixed RX thread blocking on early RX packets. Guest context support (not tested).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.8 KB
Line 
1/* $Id: DevVirtioNet.cpp 23979 2009-10-22 13:21:46Z vboxsync $ */
2/** @file
3 * DevVirtioNet - Virtio Network Device
4 *
5 */
6
7/*
8 * Copyright (C) 2009 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24#define LOG_GROUP LOG_GROUP_DEV_VIRTIO_NET
25
26#include <iprt/ctype.h>
27#ifdef IN_RING3
28# include <iprt/mem.h>
29#endif /* IN_RING3 */
30#include <iprt/param.h>
31#include <iprt/semaphore.h>
32#include <VBox/pdmdev.h>
33#include <VBox/tm.h>
34#include "../Builtins.h"
35#if 0
36#include <iprt/crc32.h>
37#include <iprt/string.h>
38#include <VBox/vm.h>
39#endif
40
41// TODO: move declarations to the header file: #include "DevVirtioNet.h"
42
43#define INSTANCE(pState) pState->szInstance
44#define IFACE_TO_STATE(pIface, ifaceName) ((VPCISTATE *)((char*)pIface - RT_OFFSETOF(VPCISTATE, ifaceName)))
45
46#define VIRTIO_RELOCATE(p, o) *(RTHCUINTPTR *)&p += o
47
48#ifdef DEBUG
49#define QUEUENAME(s, q) g_VPCIDevices[s->enmDevType].pfnGetQueueName(s, q)
50#endif /* DEBUG */
51
52//- TODO: Move to Virtio.h ----------------------------------------------------
53
54#define VPCI_F_NOTIFY_ON_EMPTY 0x01000000
55#define VPCI_F_BAD_FEATURE 0x40000000
56
57#define VRINGDESC_MAX_SIZE (2 * 1024 * 1024)
58#define VRINGDESC_F_NEXT 0x01
59#define VRINGDESC_F_WRITE 0x02
60
61struct VRingDesc
62{
63 uint64_t u64Addr;
64 uint32_t uLen;
65 uint16_t u16Flags;
66 uint16_t u16Next;
67};
68typedef struct VRingDesc VRINGDESC;
69typedef VRINGDESC *PVRINGDESC;
70
71#define VRINGAVAIL_F_NO_INTERRUPT 0x01
72
73struct VRingAvail
74{
75 uint16_t uFlags;
76 uint16_t uNextFreeIndex;
77 uint16_t auRing[1];
78};
79typedef struct VRingAvail VRINGAVAIL;
80
81struct VRingUsedElem
82{
83 uint32_t uId;
84 uint32_t uLen;
85};
86typedef struct VRingUsedElem VRINGUSEDELEM;
87
88#define VRINGUSED_F_NO_NOTIFY 0x01
89
90struct VRingUsed
91{
92 uint16_t uFlags;
93 uint16_t uIndex;
94 VRINGUSEDELEM aRing[1];
95};
96typedef struct VRingUsed VRINGUSED;
97typedef VRINGUSED *PVRINGUSED;
98
99#define VRING_MAX_SIZE 1024
100
101struct VRing
102{
103 uint16_t uSize;
104 RTGCPHYS addrDescriptors;
105 RTGCPHYS addrAvail;
106 RTGCPHYS addrUsed;
107};
108typedef struct VRing VRING;
109typedef VRING *PVRING;
110
111struct VQueue
112{
113 VRING VRing;
114 uint16_t uNextAvailIndex;
115 uint16_t uNextUsedIndex;
116 uint16_t uPageNumber;
117 void (*pfnCallback)(void *pvState, struct VQueue *pQueue);
118};
119typedef struct VQueue VQUEUE;
120typedef VQUEUE *PVQUEUE;
121
122struct VQueueElemSeg
123{
124 RTGCPHYS addr;
125 void *pv;
126 uint32_t cb;
127};
128typedef struct VQueueElemSeg VQUEUESEG;
129
130struct VQueueElem
131{
132 uint32_t uIndex;
133 uint32_t nIn;
134 uint32_t nOut;
135 VQUEUESEG aSegsIn[VRING_MAX_SIZE];
136 VQUEUESEG aSegsOut[VRING_MAX_SIZE];
137};
138typedef struct VQueueElem VQUEUEELEM;
139typedef VQUEUEELEM *PVQUEUEELEM;
140
141
142enum VirtioDeviceType
143{
144 VIRTIO_NET_ID = 0,
145 VIRTIO_BLK_ID = 1
146};
147
148struct VPCIState_st
149{
150 PDMCRITSECT cs; /**< Critical section - what is it protecting? */
151 /* Read-only part, never changes after initialization. */
152 VirtioDeviceType enmDevType; /**< Device type: net or blk. */
153 char szInstance[8]; /**< Instance name, e.g. VNet#1. */
154
155 PDMIBASE IBase;
156 PDMILEDPORTS ILeds; /**< LED interface */
157 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
158
159 PPDMDEVINSR3 pDevInsR3; /**< Device instance - R3. */
160 PPDMDEVINSR0 pDevInsR0; /**< Device instance - R0. */
161 PPDMDEVINSRC pDevInsRC; /**< Device instance - RC. */
162
163 /** TODO */
164 PCIDEVICE pciDevice;
165 /** Base port of I/O space region. */
166 RTIOPORT addrIOPort;
167
168 /* Read/write part, protected with critical section. */
169 /** Status LED. */
170 PDMLED led;
171
172 uint32_t uGuestFeatures;
173 uint16_t uQueueSelector; /**< An index in aQueues array. */
174 uint8_t uStatus; /**< Device Status (bits are device-specific). */
175 uint8_t uISR; /**< Interrupt Status Register. */
176 PVQUEUE pQueues;
177
178#if defined(VBOX_WITH_STATISTICS)
179 STAMPROFILEADV StatIOReadGC;
180 STAMPROFILEADV StatIOReadHC;
181 STAMPROFILEADV StatIOWriteGC;
182 STAMPROFILEADV StatIOWriteHC;
183 STAMCOUNTER StatIntsRaised;
184#endif /* VBOX_WITH_STATISTICS */
185};
186typedef struct VPCIState_st VPCISTATE;
187typedef VPCISTATE *PVPCISTATE;
188
189//- TODO: Move to VirtioPCI.cpp -----------------------------------------------
190
191/*****************************************************************************/
192RT_C_DECLS_BEGIN
193PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pState);
194PDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pState);
195PDMBOTHCBDECL(void) vnetSetHostFeatures(void *pState, uint32_t uFeatures);
196PDMBOTHCBDECL(int) vnetGetConfig(void *pState, uint32_t port, uint32_t cb, void *data);
197PDMBOTHCBDECL(int) vnetSetConfig(void *pState, uint32_t port, uint32_t cb, void *data);
198PDMBOTHCBDECL(void) vnetReset(void *pState);
199PDMBOTHCBDECL(void) vnetReady(void *pState);
200#ifdef DEBUG
201static const char *vnetGetQueueName(void *pvState, PVQUEUE pQueue);
202#endif /* DEBUG */
203RT_C_DECLS_END
204
205/*****************************************************************************/
206
207struct VirtioPCIDevices
208{
209 uint16_t uPCIVendorId;
210 uint16_t uPCIDeviceId;
211 uint16_t uPCISubsystemVendorId;
212 uint16_t uPCISubsystemId;
213 uint16_t uPCIClass;
214 unsigned nQueues;
215 const char *pcszName;
216 const char *pcszNameFmt;
217 uint32_t (*pfnGetHostFeatures)(void *pvState);
218 uint32_t (*pfnGetHostMinimalFeatures)(void *pvState);
219 void (*pfnSetHostFeatures)(void *pvState, uint32_t uFeatures);
220 int (*pfnGetConfig)(void *pvState, uint32_t port, uint32_t cb, void *data);
221 int (*pfnSetConfig)(void *pvState, uint32_t port, uint32_t cb, void *data);
222 void (*pfnReset)(void *pvState);
223 void (*pfnReady)(void *pvState);
224#ifdef DEBUG
225 const char *(*pfnGetQueueName)(void *pvState, PVQUEUE pQueue);
226#endif /* DEBUG */
227} g_VPCIDevices[] =
228{
229 /* Vendor Device SSVendor SubSys Class NQ Name Instance */
230 { /* Virtio Network Device */
231 0x1AF4, 0x1000, 0x1AF4, 1 + VIRTIO_NET_ID, 0x0200, 3, "virtio-net", "vnet%d",
232 vnetGetHostFeatures, vnetGetHostMinimalFeatures, vnetSetHostFeatures,
233 vnetGetConfig, vnetSetConfig, vnetReset, vnetReady
234#ifdef DEBUG
235 , vnetGetQueueName
236#endif /* DEBUG */
237 },
238 { /* Virtio Block Device */
239 0x1AF4, 0x1001, 0x1AF4, 1 + VIRTIO_BLK_ID, 0x0180, 2, "virtio-blk", "vblk%d",
240 NULL, NULL, NULL, NULL, NULL, NULL, NULL
241#ifdef DEBUG
242 , NULL
243#endif /* DEBUG */
244 },
245};
246
247
248/*****************************************************************************/
249
250#define VPCI_HOST_FEATURES 0x0
251#define VPCI_GUEST_FEATURES 0x4
252#define VPCI_QUEUE_PFN 0x8
253#define VPCI_QUEUE_NUM 0xC
254#define VPCI_QUEUE_SEL 0xE
255#define VPCI_QUEUE_NOTIFY 0x10
256#define VPCI_STATUS 0x12
257#define VPCI_ISR 0x13
258#define VPCI_ISR_QUEUE 0x1
259#define VPCI_ISR_CONFIG 0x3
260#define VPCI_CONFIG 0x14
261
262#define VPCI_STATUS_ACK 0x01
263#define VPCI_STATUS_DRV 0x02
264#define VPCI_STATUS_DRV_OK 0x04
265#define VPCI_STATUS_FAILED 0x80
266
267/** @todo use+extend RTNETIPV4 */
268
269/** @todo use+extend RTNETTCP */
270
271#ifndef VBOX_DEVICE_STRUCT_TESTCASE
272
273/* Forward declarations ******************************************************/
274RT_C_DECLS_BEGIN
275PDMBOTHCBDECL(int) vpciIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
276PDMBOTHCBDECL(int) vpciIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
277PDMBOTHCBDECL(int) vpciRaiseInterrupt(VPCISTATE *pState, int rcBusy, uint8_t u8IntCause);
278RT_C_DECLS_END
279
280
281static void vqueueReset(PVQUEUE pQueue)
282{
283 pQueue->VRing.addrDescriptors = 0;
284 pQueue->VRing.addrAvail = 0;
285 pQueue->VRing.addrUsed = 0;
286 pQueue->uNextAvailIndex = 0;
287 pQueue->uNextUsedIndex = 0;
288 pQueue->uPageNumber = 0;
289}
290
291static void vqueueInit(PVQUEUE pQueue, uint32_t uPageNumber)
292{
293 pQueue->VRing.addrDescriptors = uPageNumber << PAGE_SHIFT;
294 pQueue->VRing.addrAvail = pQueue->VRing.addrDescriptors
295 + sizeof(VRINGDESC) * pQueue->VRing.uSize;
296 pQueue->VRing.addrUsed = RT_ALIGN(
297 pQueue->VRing.addrAvail + RT_OFFSETOF(VRINGAVAIL, auRing[pQueue->VRing.uSize]),
298 PAGE_SIZE); /* The used ring must start from the next page. */
299 pQueue->uNextAvailIndex = 0;
300 pQueue->uNextUsedIndex = 0;
301}
302
303uint16_t vringReadAvailIndex(PVPCISTATE pState, PVRING pVRing)
304{
305 uint16_t tmp;
306
307 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
308 pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, uNextFreeIndex),
309 &tmp, sizeof(tmp));
310 return tmp;
311}
312
313DECLINLINE(bool) vqueueIsReady(PVPCISTATE pState, PVQUEUE pQueue)
314{
315 return !!pQueue->VRing.addrAvail;
316}
317
318DECLINLINE(bool) vqueueIsEmpty(PVPCISTATE pState, PVQUEUE pQueue)
319{
320 return (vringReadAvailIndex(pState, &pQueue->VRing) == pQueue->uNextAvailIndex);
321}
322
323void vqueueElemFree(PVQUEUEELEM pElem)
324{
325}
326
327void vringReadDesc(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex, PVRINGDESC pDesc)
328{
329 //Log(("%s vringReadDesc: ring=%p idx=%u\n", INSTANCE(pState), pVRing, uIndex));
330 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
331 pVRing->addrDescriptors + sizeof(VRINGDESC) * (uIndex % pVRing->uSize),
332 pDesc, sizeof(VRINGDESC));
333}
334
335uint16_t vringReadAvail(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex)
336{
337 uint16_t tmp;
338
339 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
340 pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, auRing[uIndex % pVRing->uSize]),
341 &tmp, sizeof(tmp));
342 return tmp;
343}
344
345uint16_t vringReadAvailFlags(PVPCISTATE pState, PVRING pVRing)
346{
347 uint16_t tmp;
348
349 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
350 pVRing->addrAvail + RT_OFFSETOF(VRINGAVAIL, uFlags),
351 &tmp, sizeof(tmp));
352 return tmp;
353}
354
355DECLINLINE(void) vringSetNotification(PVPCISTATE pState, PVRING pVRing, bool fEnabled)
356{
357 uint16_t tmp;
358
359 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
360 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uFlags),
361 &tmp, sizeof(tmp));
362
363 if (fEnabled)
364 tmp &= ~ VRINGUSED_F_NO_NOTIFY;
365 else
366 tmp |= VRINGUSED_F_NO_NOTIFY;
367
368 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
369 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uFlags),
370 &tmp, sizeof(tmp));
371}
372
373bool vqueueGet(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem)
374{
375 if (vqueueIsEmpty(pState, pQueue))
376 return false;
377
378 pElem->nIn = pElem->nOut = 0;
379
380 Log2(("%s vqueueGet: %s avail_idx=%u\n", INSTANCE(pState),
381 QUEUENAME(pState, pQueue), pQueue->uNextAvailIndex));
382
383 VRINGDESC desc;
384 uint16_t idx = vringReadAvail(pState, &pQueue->VRing, pQueue->uNextAvailIndex++);
385 pElem->uIndex = idx;
386 do
387 {
388 VQUEUESEG *pSeg;
389
390 vringReadDesc(pState, &pQueue->VRing, idx, &desc);
391 if (desc.u16Flags & VRINGDESC_F_WRITE)
392 {
393 Log2(("%s vqueueGet: %s IN seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),
394 QUEUENAME(pState, pQueue), pElem->nIn, idx, desc.u64Addr, desc.uLen));
395 pSeg = &pElem->aSegsIn[pElem->nIn++];
396 }
397 else
398 {
399 Log2(("%s vqueueGet: %s OUT seg=%u desc_idx=%u addr=%p cb=%u\n", INSTANCE(pState),
400 QUEUENAME(pState, pQueue), pElem->nOut, idx, desc.u64Addr, desc.uLen));
401 pSeg = &pElem->aSegsOut[pElem->nOut++];
402 }
403
404 pSeg->addr = desc.u64Addr;
405 pSeg->cb = desc.uLen;
406 pSeg->pv = NULL;
407
408 idx = desc.u16Next;
409 } while (desc.u16Flags & VRINGDESC_F_NEXT);
410
411 Log2(("%s vqueueGet: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pState),
412 QUEUENAME(pState, pQueue), pElem->uIndex, pElem->nIn, pElem->nOut));
413 return true;
414}
415
416uint16_t vringReadUsedIndex(PVPCISTATE pState, PVRING pVRing)
417{
418 uint16_t tmp;
419 PDMDevHlpPhysRead(pState->CTX_SUFF(pDevIns),
420 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uIndex),
421 &tmp, sizeof(tmp));
422 return tmp;
423}
424
425void vringWriteUsedIndex(PVPCISTATE pState, PVRING pVRing, uint16_t u16Value)
426{
427 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
428 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, uIndex),
429 &u16Value, sizeof(u16Value));
430}
431
432void vringWriteUsedElem(PVPCISTATE pState, PVRING pVRing, uint32_t uIndex, uint32_t uId, uint32_t uLen)
433{
434 VRINGUSEDELEM elem;
435
436 elem.uId = uId;
437 elem.uLen = uLen;
438 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns),
439 pVRing->addrUsed + RT_OFFSETOF(VRINGUSED, aRing[uIndex % pVRing->uSize]),
440 &elem, sizeof(elem));
441}
442
443void vqueuePut(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, uint32_t uLen)
444{
445 unsigned int i, uOffset;
446
447 Log2(("%s vqueuePut: %s desc_idx=%u acb=%u\n", INSTANCE(pState),
448 QUEUENAME(pState, pQueue), pElem->uIndex, uLen));
449 for (i = uOffset = 0; i < pElem->nIn && uOffset < uLen; i++)
450 {
451 uint32_t cbSegLen = RT_MIN(uLen - uOffset, pElem->aSegsIn[i].cb);
452 if (pElem->aSegsIn[i].pv)
453 {
454 Log2(("%s vqueuePut: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n", INSTANCE(pState),
455 QUEUENAME(pState, pQueue), pQueue->uNextUsedIndex, i, pElem->aSegsIn[i].addr, pElem->aSegsIn[i].pv, pElem->aSegsIn[i].cb, cbSegLen));
456 PDMDevHlpPhysWrite(pState->CTX_SUFF(pDevIns), pElem->aSegsIn[i].addr,
457 pElem->aSegsIn[i].pv, cbSegLen);
458 }
459 uOffset += cbSegLen;
460 }
461
462 Log2(("%s vqueuePut: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n", INSTANCE(pState),
463 QUEUENAME(pState, pQueue), pQueue->uNextUsedIndex, vringReadUsedIndex(pState, &pQueue->VRing), pElem->uIndex, uLen));
464 vringWriteUsedElem(pState, &pQueue->VRing, pQueue->uNextUsedIndex++, pElem->uIndex, uLen);
465}
466
467void vqueueNotify(PVPCISTATE pState, PVQUEUE pQueue)
468{
469 LogFlow(("%s vqueueNotify: %s availFlags=%x guestFeatures=%x vqueue is %sempty\n",
470 INSTANCE(pState), QUEUENAME(pState, pQueue),
471 vringReadAvailFlags(pState, &pQueue->VRing),
472 pState->uGuestFeatures, vqueueIsEmpty(pState, pQueue)?"":"not "));
473 if (!(vringReadAvailFlags(pState, &pQueue->VRing) & VRINGAVAIL_F_NO_INTERRUPT)
474 || ((pState->uGuestFeatures & VPCI_F_NOTIFY_ON_EMPTY) && vqueueIsEmpty(pState, pQueue)))
475 {
476 int rc = vpciRaiseInterrupt(pState, VERR_INTERNAL_ERROR, VPCI_ISR_QUEUE);
477 if (RT_FAILURE(rc))
478 Log(("%s vqueueNotify: Failed to raise an interrupt (%Vrc).\n", INSTANCE(pState), rc));
479 }
480}
481
482void vqueueSync(PVPCISTATE pState, PVQUEUE pQueue)
483{
484 Log2(("%s vqueueSync: %s old_used_idx=%u new_used_idx=%u\n", INSTANCE(pState),
485 QUEUENAME(pState, pQueue), vringReadUsedIndex(pState, &pQueue->VRing), pQueue->uNextUsedIndex));
486 vringWriteUsedIndex(pState, &pQueue->VRing, pQueue->uNextUsedIndex);
487 vqueueNotify(pState, pQueue);
488}
489
490void vpciReset(PVPCISTATE pState)
491{
492 pState->uGuestFeatures = 0;
493 pState->uQueueSelector = 0;
494 pState->uStatus = 0;
495 pState->uISR = 0;
496
497 for (unsigned i = 0; i < g_VPCIDevices[pState->enmDevType].nQueues; i++)
498 vqueueReset(&pState->pQueues[i]);
499}
500
501/**
502 * Arm a timer.
503 *
504 * @param pState Pointer to the device state structure.
505 * @param pTimer Pointer to the timer.
506 * @param uExpireIn Expiration interval in microseconds.
507 */
508DECLINLINE(void) vpciArmTimer(VPCISTATE *pState, PTMTIMER pTimer, uint32_t uExpireIn)
509{
510 Log2(("%s Arming timer to fire in %d usec...\n",
511 INSTANCE(pState), uExpireIn));
512 TMTimerSet(pTimer, TMTimerFromMicro(pTimer, uExpireIn) +
513 TMTimerGet(pTimer));
514}
515
516
517DECLINLINE(int) vpciCsEnter(VPCISTATE *pState, int iBusyRc)
518{
519 return PDMCritSectEnter(&pState->cs, iBusyRc);
520}
521
522DECLINLINE(void) vpciCsLeave(VPCISTATE *pState)
523{
524 PDMCritSectLeave(&pState->cs);
525}
526
527/**
528 * Raise interrupt.
529 *
530 * @param pState The device state structure.
531 * @param rcBusy Status code to return when the critical section is busy.
532 * @param u8IntCause Interrupt cause bit mask to set in PCI ISR port.
533 */
534PDMBOTHCBDECL(int) vpciRaiseInterrupt(VPCISTATE *pState, int rcBusy, uint8_t u8IntCause)
535{
536 int rc = vpciCsEnter(pState, rcBusy);
537 if (RT_UNLIKELY(rc != VINF_SUCCESS))
538 return rc;
539
540 LogFlow(("%s vpciRaiseInterrupt: u8IntCause=%x\n",
541 INSTANCE(pState), u8IntCause));
542
543 pState->uISR |= u8IntCause;
544 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 1);
545 vpciCsLeave(pState);
546 return VINF_SUCCESS;
547}
548
549/**
550 * Lower interrupt.
551 *
552 * @param pState The device state structure.
553 */
554PDMBOTHCBDECL(void) vpciLowerInterrupt(VPCISTATE *pState)
555{
556 LogFlow(("%s vpciLowerInterrupt\n", INSTANCE(pState)));
557 PDMDevHlpPCISetIrq(pState->CTX_SUFF(pDevIns), 0, 0);
558}
559
560DECLINLINE(uint32_t) vpciGetHostFeatures(PVPCISTATE pState)
561{
562 return g_VPCIDevices[pState->enmDevType].pfnGetHostFeatures(pState)
563 | VPCI_F_NOTIFY_ON_EMPTY;
564}
565
566/**
567 * Port I/O Handler for IN operations.
568 *
569 * @returns VBox status code.
570 *
571 * @param pDevIns The device instance.
572 * @param pvUser Pointer to the device state structure.
573 * @param port Port number used for the IN operation.
574 * @param pu32 Where to store the result.
575 * @param cb Number of bytes read.
576 * @thread EMT
577 */
578PDMBOTHCBDECL(int) vpciIOPortIn(PPDMDEVINS pDevIns, void *pvUser,
579 RTIOPORT port, uint32_t *pu32, unsigned cb)
580{
581 VPCISTATE *pState = PDMINS_2_DATA(pDevIns, VPCISTATE *);
582 int rc = VINF_SUCCESS;
583 const char *szInst = INSTANCE(pState);
584 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatIORead), a);
585
586 port -= pState->addrIOPort;
587 switch (port)
588 {
589 case VPCI_HOST_FEATURES:
590 /* Tell the guest what features we support. */
591 *pu32 = vpciGetHostFeatures(pState) | VPCI_F_BAD_FEATURE;
592 break;
593
594 case VPCI_GUEST_FEATURES:
595 *pu32 = pState->uGuestFeatures;
596 break;
597
598 case VPCI_QUEUE_PFN:
599 *pu32 = pState->pQueues[pState->uQueueSelector].uPageNumber;
600 break;
601
602 case VPCI_QUEUE_NUM:
603 Assert(cb == 2);
604 *(uint16_t*)pu32 = pState->pQueues[pState->uQueueSelector].VRing.uSize;
605 break;
606
607 case VPCI_QUEUE_SEL:
608 Assert(cb == 2);
609 *(uint16_t*)pu32 = pState->uQueueSelector;
610 break;
611
612 case VPCI_STATUS:
613 Assert(cb == 1);
614 *(uint8_t*)pu32 = pState->uStatus;
615 break;
616
617 case VPCI_ISR:
618 Assert(cb == 1);
619 *(uint8_t*)pu32 = pState->uISR;
620 pState->uISR = 0; /* read clears all interrupts */
621 vpciLowerInterrupt(pState);
622 break;
623
624 default:
625 if (port >= VPCI_CONFIG)
626 rc = g_VPCIDevices[pState->enmDevType].pfnGetConfig(pState, port - VPCI_CONFIG, cb, pu32);
627 else
628 {
629 *pu32 = 0xFFFFFFFF;
630 rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "%s virtioIOPortIn: no valid port at offset port=%RTiop cb=%08x\n", szInst, port, cb);
631 }
632 break;
633 }
634 Log3(("%s virtioIOPortIn: At %RTiop in %0*x\n", szInst, port, cb*2, *pu32));
635 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatIORead), a);
636 return rc;
637}
638
639
640/**
641 * Port I/O Handler for OUT operations.
642 *
643 * @returns VBox status code.
644 *
645 * @param pDevIns The device instance.
646 * @param pvUser User argument.
647 * @param Port Port number used for the IN operation.
648 * @param u32 The value to output.
649 * @param cb The value size in bytes.
650 * @thread EMT
651 */
652PDMBOTHCBDECL(int) vpciIOPortOut(PPDMDEVINS pDevIns, void *pvUser,
653 RTIOPORT port, uint32_t u32, unsigned cb)
654{
655 VPCISTATE *pState = PDMINS_2_DATA(pDevIns, VPCISTATE *);
656 int rc = VINF_SUCCESS;
657 const char *szInst = INSTANCE(pState);
658 bool fHasBecomeReady;
659 STAM_PROFILE_ADV_START(&pState->CTXSUFF(StatIOWrite), a);
660
661 port -= pState->addrIOPort;
662 Log3(("%s virtioIOPortOut: At %RTiop out %0*x\n", szInst, port, cb*2, u32));
663
664 switch (port)
665 {
666 case VPCI_GUEST_FEATURES:
667 /* Check if the guest negotiates properly, fall back to basics if it does not. */
668 if (VPCI_F_BAD_FEATURE & u32)
669 {
670 Log(("%s WARNING! Guest failed to negotiate properly (guest=%x)\n",
671 INSTANCE(pState), u32));
672 pState->uGuestFeatures = g_VPCIDevices[pState->enmDevType].pfnGetHostMinimalFeatures(pState);
673 }
674 /* The guest may potentially desire features we don't support! */
675 else if (~vpciGetHostFeatures(pState) & u32)
676 {
677 Log(("%s Guest asked for features host does not support! (host=%x guest=%x)\n",
678 INSTANCE(pState), vpciGetHostFeatures(pState), u32));
679 pState->uGuestFeatures = vpciGetHostFeatures(pState);
680 }
681 else
682 pState->uGuestFeatures = u32;
683 g_VPCIDevices[pState->enmDevType].pfnSetHostFeatures(pState, pState->uGuestFeatures);
684 break;
685
686 case VPCI_QUEUE_PFN:
687 /*
688 * The guest is responsible for allocating the pages for queues,
689 * here it provides us with the page number of descriptor table.
690 * Note that we provide the size of the queue to the guest via
691 * VIRTIO_PCI_QUEUE_NUM.
692 */
693 pState->pQueues[pState->uQueueSelector].uPageNumber = u32;
694 if (u32)
695 vqueueInit(&pState->pQueues[pState->uQueueSelector], u32);
696 else
697 g_VPCIDevices[pState->enmDevType].pfnReset(pState);
698 break;
699
700 case VPCI_QUEUE_SEL:
701 Assert(cb == 2);
702 u32 &= 0xFFFF;
703 if (u32 < g_VPCIDevices[pState->enmDevType].nQueues)
704 pState->uQueueSelector = u32;
705 else
706 Log3(("%s virtioIOPortOut: Invalid queue selector %08x\n", szInst, u32));
707 break;
708
709 case VPCI_QUEUE_NOTIFY:
710 Assert(cb == 2);
711 u32 &= 0xFFFF;
712 if (u32 < g_VPCIDevices[pState->enmDevType].nQueues)
713 if (pState->pQueues[u32].VRing.addrDescriptors)
714 pState->pQueues[u32].pfnCallback(pState, &pState->pQueues[u32]);
715 else
716 Log(("%s The queue (#%d) being notified has not been initialized.\n",
717 INSTANCE(pState), u32));
718 else
719 Log(("%s Invalid queue number (%d)\n", INSTANCE(pState), u32));
720 break;
721
722 case VPCI_STATUS:
723 Assert(cb == 1);
724 u32 &= 0xFF;
725 fHasBecomeReady = !(pState->uStatus & VPCI_STATUS_DRV_OK) && (u32 & VPCI_STATUS_DRV_OK);
726 pState->uStatus = u32;
727 /* Writing 0 to the status port triggers device reset. */
728 if (u32 == 0)
729 g_VPCIDevices[pState->enmDevType].pfnReset(pState);
730 else if (fHasBecomeReady)
731 g_VPCIDevices[pState->enmDevType].pfnReady(pState);
732 break;
733
734 default:
735 if (port >= VPCI_CONFIG)
736 rc = g_VPCIDevices[pState->enmDevType].pfnSetConfig(pState, port - VPCI_CONFIG, cb, &u32);
737 else
738 rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "%s virtioIOPortOut: no valid port at offset port=%RTiop cb=%08x\n", szInst, port, cb);
739 break;
740 }
741
742 STAM_PROFILE_ADV_STOP(&pState->CTXSUFF(StatIOWrite), a);
743 return rc;
744}
745
746#ifdef IN_RING3
747// Common
748/**
749 * Map PCI I/O region.
750 *
751 * @return VBox status code.
752 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
753 * @param iRegion The region number.
754 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
755 * I/O port, else it's a physical address.
756 * This address is *NOT* relative to pci_mem_base like earlier!
757 * @param cb Region size.
758 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
759 * @thread EMT
760 */
761static DECLCALLBACK(int) vpciMap(PPCIDEVICE pPciDev, int iRegion,
762 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
763{
764 int rc;
765 VPCISTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, VPCISTATE*);
766
767 if (enmType != PCI_ADDRESS_SPACE_IO)
768 {
769 /* We should never get here */
770 AssertMsgFailed(("Invalid PCI address space param in map callback"));
771 return VERR_INTERNAL_ERROR;
772 }
773
774 pState->addrIOPort = (RTIOPORT)GCPhysAddress;
775 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->addrIOPort, cb, 0,
776 vpciIOPortOut, vpciIOPortIn, NULL, NULL, "VirtioNet");
777#if 0
778 AssertRCReturn(rc, rc);
779 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->addrIOPort, cb, 0,
780 "vpciIOPortOut", "vpciIOPortIn", NULL, NULL, "VirtioNet");
781 AssertRCReturn(rc, rc);
782 rc = PDMDevHlpIOPortRegisterGC(pPciDev->pDevIns, pState->addrIOPort, cb, 0,
783 "vpciIOPortOut", "vpciIOPortIn", NULL, NULL, "VirtioNet");
784#endif
785 AssertRC(rc);
786 return rc;
787}
788
789/**
790 * Provides interfaces to the driver.
791 *
792 * @returns Pointer to interface. NULL if the interface is not supported.
793 * @param pInterface Pointer to this interface structure.
794 * @param enmInterface The requested interface identification.
795 * @thread EMT
796 */
797static DECLCALLBACK(void *) vpciQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
798{
799 VPCISTATE *pState = IFACE_TO_STATE(pInterface, IBase);
800 Assert(&pState->IBase == pInterface);
801 switch (enmInterface)
802 {
803 case PDMINTERFACE_BASE:
804 return &pState->IBase;
805 case PDMINTERFACE_LED_PORTS:
806 return &pState->ILeds;
807 default:
808 return NULL;
809 }
810}
811
812/**
813 * Gets the pointer to the status LED of a unit.
814 *
815 * @returns VBox status code.
816 * @param pInterface Pointer to the interface structure.
817 * @param iLUN The unit which status LED we desire.
818 * @param ppLed Where to store the LED pointer.
819 * @thread EMT
820 */
821static DECLCALLBACK(int) vpciQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
822{
823 VPCISTATE *pState = IFACE_TO_STATE(pInterface, ILeds);
824 int rc = VERR_PDM_LUN_NOT_FOUND;
825
826 if (iLUN == 0)
827 {
828 *ppLed = &pState->led;
829 rc = VINF_SUCCESS;
830 }
831 return rc;
832}
833
834/**
835 * Turns on/off the write status LED.
836 *
837 * @returns VBox status code.
838 * @param pState Pointer to the device state structure.
839 * @param fOn New LED state.
840 */
841void vpciSetWriteLed(PVPCISTATE pState, bool fOn)
842{
843 LogFlow(("%s vpciSetWriteLed: %s\n", INSTANCE(pState), fOn?"on":"off"));
844 if (fOn)
845 pState->led.Asserted.s.fWriting = pState->led.Actual.s.fWriting = 1;
846 else
847 pState->led.Actual.s.fWriting = fOn;
848}
849
850/**
851 * Turns on/off the read status LED.
852 *
853 * @returns VBox status code.
854 * @param pState Pointer to the device state structure.
855 * @param fOn New LED state.
856 */
857void vpciSetReadLed(PVPCISTATE pState, bool fOn)
858{
859 LogFlow(("%s vpciSetReadLed: %s\n", INSTANCE(pState), fOn?"on":"off"));
860 if (fOn)
861 pState->led.Asserted.s.fReading = pState->led.Actual.s.fReading = 1;
862 else
863 pState->led.Actual.s.fReading = fOn;
864}
865
866/**
867 * Sets 8-bit register in PCI configuration space.
868 * @param refPciDev The PCI device.
869 * @param uOffset The register offset.
870 * @param u16Value The value to store in the register.
871 * @thread EMT
872 */
873DECLINLINE(void) vpciCfgSetU8(PCIDEVICE& refPciDev, uint32_t uOffset, uint8_t u8Value)
874{
875 Assert(uOffset < sizeof(refPciDev.config));
876 refPciDev.config[uOffset] = u8Value;
877}
878
879/**
880 * Sets 16-bit register in PCI configuration space.
881 * @param refPciDev The PCI device.
882 * @param uOffset The register offset.
883 * @param u16Value The value to store in the register.
884 * @thread EMT
885 */
886DECLINLINE(void) vpciCfgSetU16(PCIDEVICE& refPciDev, uint32_t uOffset, uint16_t u16Value)
887{
888 Assert(uOffset+sizeof(u16Value) <= sizeof(refPciDev.config));
889 *(uint16_t*)&refPciDev.config[uOffset] = u16Value;
890}
891
892/**
893 * Sets 32-bit register in PCI configuration space.
894 * @param refPciDev The PCI device.
895 * @param uOffset The register offset.
896 * @param u32Value The value to store in the register.
897 * @thread EMT
898 */
899DECLINLINE(void) vpciCfgSetU32(PCIDEVICE& refPciDev, uint32_t uOffset, uint32_t u32Value)
900{
901 Assert(uOffset+sizeof(u32Value) <= sizeof(refPciDev.config));
902 *(uint32_t*)&refPciDev.config[uOffset] = u32Value;
903}
904
905
906/**
907 * Set PCI configuration space registers.
908 *
909 * @param pci Reference to PCI device structure.
910 * @thread EMT
911 */
912static DECLCALLBACK(void) vpciConfigure(PCIDEVICE& pci, VirtioDeviceType enmType)
913{
914 Assert(enmType < (int)RT_ELEMENTS(g_VPCIDevices));
915 /* Configure PCI Device, assume 32-bit mode ******************************/
916 PCIDevSetVendorId(&pci, g_VPCIDevices[enmType].uPCIVendorId);
917 PCIDevSetDeviceId(&pci, g_VPCIDevices[enmType].uPCIDeviceId);
918 vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_VPCIDevices[enmType].uPCISubsystemVendorId);
919 vpciCfgSetU16(pci, VBOX_PCI_SUBSYSTEM_ID, g_VPCIDevices[enmType].uPCISubsystemId);
920
921 /* ABI version, must be equal 0 as of 2.6.30 kernel. */
922 vpciCfgSetU8( pci, VBOX_PCI_REVISION_ID, 0x00);
923 /* Ethernet adapter */
924 vpciCfgSetU8( pci, VBOX_PCI_CLASS_PROG, 0x00);
925 vpciCfgSetU16(pci, VBOX_PCI_CLASS_DEVICE, g_VPCIDevices[enmType].uPCIClass);
926 /* Interrupt Pin: INTA# */
927 vpciCfgSetU8( pci, VBOX_PCI_INTERRUPT_PIN, 0x01);
928}
929
930// TODO: header
931DECLCALLBACK(int) vpciConstruct(PPDMDEVINS pDevIns, VPCISTATE *pState,
932 int iInstance, VirtioDeviceType enmDevType,
933 unsigned uConfigSize)
934{
935 int rc = VINF_SUCCESS;
936 /* Init handles and log related stuff. */
937 RTStrPrintf(pState->szInstance, sizeof(pState->szInstance), g_VPCIDevices[enmDevType].pcszNameFmt, iInstance);
938 pState->enmDevType = enmDevType;
939
940 /* Allocate queues */
941 pState->pQueues = (VQUEUE*)RTMemAllocZ(sizeof(VQUEUE) * g_VPCIDevices[enmDevType].nQueues);
942
943 pState->pDevInsR3 = pDevIns;
944 pState->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
945 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
946 pState->led.u32Magic = PDMLED_MAGIC;
947
948 pState->ILeds.pfnQueryStatusLed = vpciQueryStatusLed;
949
950 /* Initialize critical section. */
951 rc = PDMDevHlpCritSectInit(pDevIns, &pState->cs, pState->szInstance);
952 if (RT_FAILURE(rc))
953 return rc;
954
955 /* Set PCI config registers */
956 vpciConfigure(pState->pciDevice, VIRTIO_NET_ID);
957 /* Register PCI device */
958 rc = PDMDevHlpPCIRegister(pDevIns, &pState->pciDevice);
959 if (RT_FAILURE(rc))
960 return rc;
961
962 /* Map our ports to IO space. */
963 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, VPCI_CONFIG + uConfigSize,
964 PCI_ADDRESS_SPACE_IO, vpciMap);
965 if (RT_FAILURE(rc))
966 return rc;
967
968 /* Status driver */
969 PPDMIBASE pBase;
970 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pState->IBase, &pBase, "Status Port");
971 if (RT_FAILURE(rc))
972 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN"));
973 pState->pLedsConnector = (PPDMILEDCONNECTORS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
974
975#if defined(VBOX_WITH_STATISTICS)
976 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in GC", "/Devices/VNet%d/IO/ReadGC", iInstance);
977 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in HC", "/Devices/VNet%d/IO/ReadHC", iInstance);
978 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in GC", "/Devices/VNet%d/IO/WriteGC", iInstance);
979 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC", "/Devices/VNet%d/IO/WriteHC", iInstance);
980 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsRaised, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of raised interrupts", "/Devices/VNet%d/Interrupts/Raised", iInstance);
981#endif /* VBOX_WITH_STATISTICS */
982
983 return rc;
984}
985
986/**
987 * Destruct PCI-related part of device.
988 *
989 * We need to free non-VM resources only.
990 *
991 * @returns VBox status.
992 * @param pState The device state structure.
993 */
994static DECLCALLBACK(int) vpciDestruct(VPCISTATE* pState)
995{
996 Log(("%s Destroying PCI instance\n", INSTANCE(pState)));
997
998 if (pState->pQueues)
999 RTMemFree(pState->pQueues);
1000
1001 if (PDMCritSectIsInitialized(&pState->cs))
1002 {
1003 PDMR3CritSectDelete(&pState->cs);
1004 }
1005 return VINF_SUCCESS;
1006}
1007
1008/**
1009 * Device relocation callback.
1010 *
1011 * When this callback is called the device instance data, and if the
1012 * device have a GC component, is being relocated, or/and the selectors
1013 * have been changed. The device must use the chance to perform the
1014 * necessary pointer relocations and data updates.
1015 *
1016 * Before the GC code is executed the first time, this function will be
1017 * called with a 0 delta so GC pointer calculations can be one in one place.
1018 *
1019 * @param pDevIns Pointer to the device instance.
1020 * @param offDelta The relocation delta relative to the old location.
1021 *
1022 * @remark A relocation CANNOT fail.
1023 */
1024static DECLCALLBACK(void) vpciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1025{
1026 VPCISTATE* pState = PDMINS_2_DATA(pDevIns, VPCISTATE*);
1027 pState->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1028 // TBD
1029}
1030
1031PVQUEUE vpciAddQueue(VPCISTATE* pState, unsigned uSize,
1032 void (*pfnCallback)(void *pvState, PVQUEUE pQueue))
1033{
1034 PVQUEUE pQueue = NULL;
1035 /* Find an empty queue slot */
1036 for (unsigned i = 0; i < g_VPCIDevices[pState->enmDevType].nQueues; i++)
1037 {
1038 if (pState->pQueues[i].VRing.uSize == 0)
1039 {
1040 pQueue = &pState->pQueues[i];
1041 break;
1042 }
1043 }
1044
1045 if (!pQueue)
1046 {
1047 Log(("%s Too many queues being added, no empty slots available!\n", INSTANCE(pState)));
1048 }
1049 else
1050 {
1051 pQueue->VRing.uSize = uSize;
1052 pQueue->VRing.addrDescriptors = 0;
1053 pQueue->uPageNumber = 0;
1054 pQueue->pfnCallback = pfnCallback;
1055 }
1056
1057 return pQueue;
1058}
1059
1060
1061#endif /* IN_RING3 */
1062
1063
1064//------------------------- Tear off here: vnet -------------------------------
1065
1066//- TODO: Move to VirtioNet.h -------------------------------------------------
1067
1068#define VNET_MAX_FRAME_SIZE 65536 // TODO: Is it the right limit?
1069#define VNET_SAVEDSTATE_VERSION 1
1070
1071/* Virtio net features */
1072#define VNET_F_CSUM 0x00000001 /* Host handles pkts w/ partial csum */
1073#define VNET_F_GUEST_CSUM 0x00000002 /* Guest handles pkts w/ partial csum */
1074#define VNET_F_MAC 0x00000020 /* Host has given MAC address. */
1075#define VNET_F_GSO 0x00000040 /* Host handles pkts w/ any GSO type */
1076#define VNET_F_GUEST_TSO4 0x00000080 /* Guest can handle TSOv4 in. */
1077#define VNET_F_GUEST_TSO6 0x00000100 /* Guest can handle TSOv6 in. */
1078#define VNET_F_GUEST_ECN 0x00000200 /* Guest can handle TSO[6] w/ ECN in. */
1079#define VNET_F_GUEST_UFO 0x00000400 /* Guest can handle UFO in. */
1080#define VNET_F_HOST_TSO4 0x00000800 /* Host can handle TSOv4 in. */
1081#define VNET_F_HOST_TSO6 0x00001000 /* Host can handle TSOv6 in. */
1082#define VNET_F_HOST_ECN 0x00002000 /* Host can handle TSO[6] w/ ECN in. */
1083#define VNET_F_HOST_UFO 0x00004000 /* Host can handle UFO in. */
1084#define VNET_F_MRG_RXBUF 0x00008000 /* Host can merge receive buffers. */
1085#define VNET_F_STATUS 0x00010000 /* virtio_net_config.status available */
1086#define VNET_F_CTRL_VQ 0x00020000 /* Control channel available */
1087#define VNET_F_CTRL_RX 0x00040000 /* Control channel RX mode support */
1088#define VNET_F_CTRL_VLAN 0x00080000 /* Control channel VLAN filtering */
1089
1090#define VNET_S_LINK_UP 1
1091
1092
1093#ifdef _MSC_VER
1094struct VNetPCIConfig
1095#else /* !_MSC_VER */
1096struct __attribute__ ((__packed__)) VNetPCIConfig
1097#endif /* !_MSC_VER */
1098{
1099 RTMAC mac;
1100 uint16_t uStatus;
1101};
1102
1103AssertCompileMemberOffset(struct VNetPCIConfig, uStatus, 6);
1104
1105/**
1106 * Device state structure. Holds the current state of device.
1107 */
1108
1109struct VNetState_st
1110{
1111 /* VPCISTATE must be the first member! */
1112 VPCISTATE VPCI;
1113
1114 PDMINETWORKPORT INetworkPort;
1115 PDMINETWORKCONFIG INetworkConfig;
1116 R3PTRTYPE(PPDMIBASE) pDrvBase; /**< Attached network driver. */
1117 R3PTRTYPE(PPDMINETWORKCONNECTOR) pDrv; /**< Connector of attached network driver. */
1118
1119 R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3; /**< Rx wakeup signaller - R3. */
1120 R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0; /**< Rx wakeup signaller - R0. */
1121 RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC; /**< Rx wakeup signaller - RC. */
1122
1123 PTMTIMERR3 pLinkUpTimer; /**< Link Up(/Restore) Timer. */
1124
1125 /** PCI config area holding MAC address as well as TBD. */
1126 struct VNetPCIConfig config;
1127 /** True if physical cable is attached in configuration. */
1128 bool fCableConnected;
1129
1130 /** Number of packet being sent/received to show in debug log. */
1131 uint32_t u32PktNo;
1132
1133 /** Locked state -- no state alteration possible. */
1134 bool fLocked;
1135
1136 PVQUEUE pRxQueue;
1137 PVQUEUE pTxQueue;
1138 PVQUEUE pCtlQueue;
1139 /* Receive-blocking-related fields ***************************************/
1140
1141 /** N/A: */
1142 bool volatile fMaybeOutOfSpace;
1143 /** EMT: Gets signalled when more RX descriptors become available. */
1144 RTSEMEVENT hEventMoreRxDescAvail;
1145
1146 /* Statistic fields ******************************************************/
1147
1148 STAMCOUNTER StatReceiveBytes;
1149 STAMCOUNTER StatTransmitBytes;
1150#if defined(VBOX_WITH_STATISTICS)
1151 STAMPROFILEADV StatReceive;
1152 STAMPROFILEADV StatTransmit;
1153 STAMPROFILEADV StatTransmitSend;
1154 STAMPROFILE StatRxOverflow;
1155 STAMCOUNTER StatRxOverflowWakeup;
1156#endif /* VBOX_WITH_STATISTICS */
1157
1158};
1159typedef struct VNetState_st VNETSTATE;
1160typedef VNETSTATE *PVNETSTATE;
1161
1162#define VNETHDR_GSO_NONE 0
1163
1164struct VNetHdr
1165{
1166 uint8_t u8Flags;
1167 uint8_t u8GSOType;
1168 uint16_t u16HdrLen;
1169 uint16_t u16GSOSize;
1170 uint16_t u16CSumStart;
1171 uint16_t u16CSumOffset;
1172};
1173typedef struct VNetHdr VNETHDR;
1174typedef VNETHDR *PVNETHDR;
1175
1176AssertCompileMemberOffset(VNETSTATE, VPCI, 0);
1177
1178//- TODO: Leave here ----------------------------------------------------------
1179
1180#undef INSTANCE
1181#define INSTANCE(pState) pState->VPCI.szInstance
1182#undef IFACE_TO_STATE
1183#define IFACE_TO_STATE(pIface, ifaceName) ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName)))
1184#define STATUS pState->config.uStatus
1185
1186#ifdef DEBUG
1187static const char *vnetGetQueueName(void *pvState, PVQUEUE pQueue)
1188{
1189 VNETSTATE *pState = (VNETSTATE *)pvState;
1190 if (pQueue == pState->pRxQueue)
1191 return "RX ";
1192 else if (pQueue == pState->pTxQueue)
1193 return "TX ";
1194 else if (pQueue == pState->pCtlQueue)
1195 return "CTL";
1196 return "Invalid";
1197}
1198#endif /* DEBUG */
1199
1200PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
1201{
1202 // TODO: implement
1203 return VNET_F_MAC | VNET_F_STATUS;
1204}
1205
1206PDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pvState)
1207{
1208 return VNET_F_MAC;
1209}
1210
1211PDMBOTHCBDECL(void) vnetSetHostFeatures(void *pvState, uint32_t uFeatures)
1212{
1213 // TODO: Nothing to do here yet
1214 VNETSTATE *pState = (VNETSTATE *)pvState;
1215 LogFlow(("%s vnetSetHostFeatures: uFeatures=%x\n", INSTANCE(pState), uFeatures));
1216}
1217
1218PDMBOTHCBDECL(int) vnetGetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
1219{
1220 VNETSTATE *pState = (VNETSTATE *)pvState;
1221 if (port + cb > sizeof(struct VNetPCIConfig))
1222 {
1223 Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
1224 return VERR_INTERNAL_ERROR;
1225 }
1226 memcpy(data, ((uint8_t*)&pState->config) + port, cb);
1227 return VINF_SUCCESS;
1228}
1229
1230PDMBOTHCBDECL(int) vnetSetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
1231{
1232 VNETSTATE *pState = (VNETSTATE *)pvState;
1233 if (port + cb > sizeof(struct VNetPCIConfig))
1234 {
1235 Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
1236 return VERR_INTERNAL_ERROR;
1237 }
1238 memcpy(((uint8_t*)&pState->config) + port, data, cb);
1239 return VINF_SUCCESS;
1240}
1241
1242/**
1243 * Hardware reset. Revert all registers to initial values.
1244 *
1245 * @param pState The device state structure.
1246 */
1247PDMBOTHCBDECL(void) vnetReset(void *pvState)
1248{
1249 VNETSTATE *pState = (VNETSTATE*)pvState;
1250 Log(("%s Reset triggered\n", INSTANCE(pState)));
1251 vpciReset(&pState->VPCI);
1252 // TODO: Implement reset
1253}
1254
1255#ifdef IN_RING3
1256/**
1257 * Wakeup the RX thread.
1258 */
1259static void vnetWakeupReceive(PPDMDEVINS pDevIns)
1260{
1261 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE *);
1262 if ( pState->fMaybeOutOfSpace
1263 && pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1264 {
1265 STAM_COUNTER_INC(&pState->StatRxOverflowWakeup);
1266 Log(("%s Waking up Out-of-RX-space semaphore\n", INSTANCE(pState)));
1267 RTSemEventSignal(pState->hEventMoreRxDescAvail);
1268 }
1269}
1270
1271/**
1272 * Link Up Timer handler.
1273 *
1274 * @param pDevIns Pointer to device instance structure.
1275 * @param pTimer Pointer to the timer.
1276 * @param pvUser NULL.
1277 * @thread EMT
1278 */
1279static DECLCALLBACK(void) vnetLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1280{
1281 VNETSTATE *pState = (VNETSTATE *)pvUser;
1282
1283 STATUS |= VNET_S_LINK_UP;
1284 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1285}
1286
1287
1288
1289
1290/**
1291 * Handler for the wakeup signaller queue.
1292 */
1293static DECLCALLBACK(bool) vnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1294{
1295 vnetWakeupReceive(pDevIns);
1296 return true;
1297}
1298
1299#endif /* IN_RING3 */
1300
1301/**
1302 * This function is called when the driver becomes ready.
1303 *
1304 * @param pState The device state structure.
1305 */
1306PDMBOTHCBDECL(void) vnetReady(void *pvState)
1307{
1308 VNETSTATE *pState = (VNETSTATE*)pvState;
1309 Log(("%s Driver became ready, waking up RX thread...\n", INSTANCE(pState)));
1310#ifdef IN_RING3
1311 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
1312#else
1313 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pCanRxQueue));
1314 if (pItem)
1315 PDMQueueInsert(pState->CTX_SUFF(pCanRxQueue), pItem);
1316#endif
1317}
1318
1319
1320#ifdef IN_RING3
1321
1322/**
1323 * Check if the device can receive data now.
1324 * This must be called before the pfnRecieve() method is called.
1325 *
1326 * @remarks As a side effect this function enables queue notification
1327 * if it cannot receive because the queue is empty.
1328 * It disables notification if it can receive.
1329 *
1330 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
1331 * @param pInterface Pointer to the interface structure containing the called function pointer.
1332 * @thread EMT
1333 */
1334static int vnetCanReceive(VNETSTATE *pState)
1335{
1336 int rc;
1337 LogFlow(("%s vnetCanReceive\n", INSTANCE(pState)));
1338 if (!(pState->VPCI.uStatus & VPCI_STATUS_DRV_OK))
1339 rc = VERR_NET_NO_BUFFER_SPACE;
1340 else if (!vqueueIsReady(&pState->VPCI, pState->pRxQueue))
1341 rc = VERR_NET_NO_BUFFER_SPACE;
1342 else if (vqueueIsEmpty(&pState->VPCI, pState->pRxQueue))
1343 {
1344 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, true);
1345 rc = VERR_NET_NO_BUFFER_SPACE;
1346 }
1347 else
1348 {
1349 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, false);
1350 rc = VINF_SUCCESS;
1351 }
1352
1353 LogFlow(("%s vnetCanReceive -> %Vrc\n", INSTANCE(pState), rc));
1354 return rc;
1355}
1356
1357static DECLCALLBACK(int) vnetWaitReceiveAvail(PPDMINETWORKPORT pInterface, unsigned cMillies)
1358{
1359 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
1360 LogFlow(("%s vnetWaitReceiveAvail(cMillies=%u)\n", INSTANCE(pState), cMillies));
1361 int rc = vnetCanReceive(pState);
1362
1363 if (RT_SUCCESS(rc))
1364 return VINF_SUCCESS;
1365 if (RT_UNLIKELY(cMillies == 0))
1366 return VERR_NET_NO_BUFFER_SPACE;
1367
1368 rc = VERR_INTERRUPTED;
1369 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, true);
1370 STAM_PROFILE_START(&pState->StatRxOverflow, a);
1371 while (RT_LIKELY(PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns)) == VMSTATE_RUNNING))
1372 {
1373 int rc2 = vnetCanReceive(pState);
1374 if (RT_SUCCESS(rc2))
1375 {
1376 rc = VINF_SUCCESS;
1377 break;
1378 }
1379 Log(("%s vnetWaitReceiveAvail: waiting cMillies=%u...\n",
1380 INSTANCE(pState), cMillies));
1381 RTSemEventWait(pState->hEventMoreRxDescAvail, cMillies);
1382 }
1383 STAM_PROFILE_STOP(&pState->StatRxOverflow, a);
1384 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, false);
1385
1386 LogFlow(("%s vnetWaitReceiveAvail -> %d\n", INSTANCE(pState), rc));
1387 return rc;
1388}
1389
1390
1391/**
1392 * Provides interfaces to the driver.
1393 *
1394 * @returns Pointer to interface. NULL if the interface is not supported.
1395 * @param pInterface Pointer to this interface structure.
1396 * @param enmInterface The requested interface identification.
1397 * @thread EMT
1398 */
1399static DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
1400{
1401 VNETSTATE *pState = IFACE_TO_STATE(pInterface, VPCI.IBase);
1402 Assert(&pState->VPCI.IBase == pInterface);
1403 switch (enmInterface)
1404 {
1405 case PDMINTERFACE_NETWORK_PORT:
1406 return &pState->INetworkPort;
1407 case PDMINTERFACE_NETWORK_CONFIG:
1408 return &pState->INetworkConfig;
1409 default:
1410 return vpciQueryInterface(pInterface, enmInterface);
1411 }
1412}
1413
1414/**
1415 * Determines if the packet is to be delivered to upper layer. The following
1416 * filters supported:
1417 * - Exact Unicast/Multicast
1418 * - Promiscuous Unicast/Multicast
1419 * - Multicast
1420 * - VLAN
1421 *
1422 * @returns true if packet is intended for this node.
1423 * @param pState Pointer to the state structure.
1424 * @param pvBuf The ethernet packet.
1425 * @param cb Number of bytes available in the packet.
1426 */
1427static bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
1428{
1429 return true; // TODO: Implement!
1430}
1431
1432/**
1433 * Pad and store received packet.
1434 *
1435 * @remarks Make sure that the packet appears to upper layer as one coming
1436 * from real Ethernet: pad it and insert FCS.
1437 *
1438 * @returns VBox status code.
1439 * @param pState The device state structure.
1440 * @param pvBuf The available data.
1441 * @param cb Number of bytes available in the buffer.
1442 */
1443static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
1444{
1445 VNETHDR hdr;
1446
1447 hdr.u8Flags = 0;
1448 hdr.u8GSOType = VNETHDR_GSO_NONE;
1449
1450 unsigned int uOffset = 0;
1451 for (unsigned int nElem = 0; uOffset < cb; nElem++)
1452 {
1453 VQUEUEELEM elem;
1454 unsigned int nSeg = 0, uElemSize = 0;
1455
1456 if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
1457 {
1458 Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
1459 return VERR_INTERNAL_ERROR;
1460 }
1461
1462 if (elem.nIn < 1)
1463 {
1464 Log(("%s vnetHandleRxPacket: No writable descriptors in receive queue!\n", INSTANCE(pState)));
1465 return VERR_INTERNAL_ERROR;
1466 }
1467
1468 if (nElem == 0)
1469 {
1470 /* The very first segment of the very first element gets the header. */
1471 if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
1472 {
1473 Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
1474 return VERR_INTERNAL_ERROR;
1475 }
1476
1477 elem.aSegsIn[nSeg++].pv = &hdr;
1478 uElemSize += sizeof(VNETHDR);
1479 }
1480
1481 while (nSeg < elem.nIn && uOffset < cb)
1482 {
1483 unsigned int uSize = RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
1484 elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
1485 uOffset += uSize;
1486 uElemSize += uSize;
1487 }
1488 vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
1489 }
1490 vqueueSync(&pState->VPCI, pState->pRxQueue);
1491
1492 return VINF_SUCCESS;
1493}
1494
1495/**
1496 * Receive data from the network.
1497 *
1498 * @returns VBox status code.
1499 * @param pInterface Pointer to the interface structure containing the called function pointer.
1500 * @param pvBuf The available data.
1501 * @param cb Number of bytes available in the buffer.
1502 * @thread ???
1503 */
1504static DECLCALLBACK(int) vnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
1505{
1506 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
1507 int rc = VINF_SUCCESS;
1508
1509 Log2(("%s vnetReceive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
1510 rc = vnetCanReceive(pState);
1511 if (RT_FAILURE(rc))
1512 return rc;
1513
1514 vpciSetReadLed(&pState->VPCI, true);
1515 if (vnetAddressFilter(pState, pvBuf, cb))
1516 {
1517 rc = vnetHandleRxPacket(pState, pvBuf, cb);
1518 }
1519 vpciSetReadLed(&pState->VPCI, false);
1520
1521 return rc;
1522}
1523
1524/**
1525 * Gets the current Media Access Control (MAC) address.
1526 *
1527 * @returns VBox status code.
1528 * @param pInterface Pointer to the interface structure containing the called function pointer.
1529 * @param pMac Where to store the MAC address.
1530 * @thread EMT
1531 */
1532static DECLCALLBACK(int) vnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
1533{
1534 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1535 memcpy(pMac, pState->config.mac.au8, sizeof(RTMAC));
1536 return VINF_SUCCESS;
1537}
1538
1539/**
1540 * Gets the new link state.
1541 *
1542 * @returns The current link state.
1543 * @param pInterface Pointer to the interface structure containing the called function pointer.
1544 * @thread EMT
1545 */
1546static DECLCALLBACK(PDMNETWORKLINKSTATE) vnetGetLinkState(PPDMINETWORKCONFIG pInterface)
1547{
1548 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1549 if (STATUS & VNET_S_LINK_UP)
1550 return PDMNETWORKLINKSTATE_UP;
1551 return PDMNETWORKLINKSTATE_DOWN;
1552}
1553
1554
1555/**
1556 * Sets the new link state.
1557 *
1558 * @returns VBox status code.
1559 * @param pInterface Pointer to the interface structure containing the called function pointer.
1560 * @param enmState The new link state
1561 */
1562static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
1563{
1564 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1565 bool fOldUp = !!(STATUS & VNET_S_LINK_UP);
1566 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
1567
1568 if (fNewUp != fOldUp)
1569 {
1570 if (fNewUp)
1571 {
1572 Log(("%s Link is up\n", INSTANCE(pState)));
1573 STATUS |= VNET_S_LINK_UP;
1574 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1575 }
1576 else
1577 {
1578 Log(("%s Link is down\n", INSTANCE(pState)));
1579 STATUS &= ~VNET_S_LINK_UP;
1580 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1581 }
1582 if (pState->pDrv)
1583 pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
1584 }
1585 return VINF_SUCCESS;
1586}
1587
1588static DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
1589{
1590 VNETSTATE *pState = (VNETSTATE*)pvState;
1591 Log(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pState)));
1592 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
1593}
1594
1595static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
1596{
1597 VNETSTATE *pState = (VNETSTATE*)pvState;
1598 if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
1599 {
1600 Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
1601 INSTANCE(pState), pState->VPCI.uStatus));
1602 return;
1603 }
1604
1605 vpciSetWriteLed(&pState->VPCI, true);
1606
1607 VQUEUEELEM elem;
1608 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1609 {
1610 unsigned int uOffset = 0;
1611 if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
1612 {
1613 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
1614 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
1615 vqueueElemFree(&elem);
1616 break; /* For now we simply ignore the header, but it must be there anyway! */
1617 }
1618 else
1619 {
1620 uint8_t *pFrame = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
1621 if (!pFrame)
1622 {
1623 Log(("%s vnetQueueTransmit: Failed to allocate %u bytes.\n",
1624 INSTANCE(pState), VNET_MAX_FRAME_SIZE));
1625 vqueueElemFree(&elem);
1626 break; /* For now we simply ignore the header, but it must be there anyway! */
1627 }
1628
1629 /* Assemble a complete frame. */
1630 for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
1631 {
1632 unsigned int uSize = elem.aSegsOut[i].cb;
1633 if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
1634 {
1635 Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
1636 uSize = VNET_MAX_FRAME_SIZE - uOffset;
1637 }
1638 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
1639 pFrame + uOffset, uSize);
1640 uOffset += uSize;
1641 }
1642 STAM_PROFILE_ADV_START(&pState->StatTransmitSend, a);
1643 int rc = pState->pDrv->pfnSend(pState->pDrv, pFrame, uOffset);
1644 STAM_PROFILE_ADV_STOP(&pState->StatTransmitSend, a);
1645 RTMemFree(pFrame);
1646 }
1647 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
1648 vqueueSync(&pState->VPCI, pQueue);
1649 }
1650 vpciSetWriteLed(&pState->VPCI, false);
1651}
1652
1653static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
1654{
1655 VNETSTATE *pState = (VNETSTATE*)pvState;
1656 Log(("%s Pending control message\n", INSTANCE(pState)));
1657}
1658
1659
1660/**
1661 * Construct a device instance for a VM.
1662 *
1663 * @returns VBox status.
1664 * @param pDevIns The device instance data.
1665 * If the registration structure is needed, pDevIns->pDevReg points to it.
1666 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1667 * The device number is also found in pDevIns->iInstance, but since it's
1668 * likely to be freqently used PDM passes it as parameter.
1669 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1670 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1671 * iInstance it's expected to be used a bit in this function.
1672 * @thread EMT
1673 */
1674static DECLCALLBACK(int) vnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1675{
1676 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1677 int rc;
1678
1679 /* Initialize PCI part first. */
1680 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface;
1681 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance, VIRTIO_NET_ID, sizeof(VNetPCIConfig));
1682 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive);
1683 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit);
1684 pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16, vnetQueueControl);
1685
1686 Log(("%s Constructing new instance\n", INSTANCE(pState)));
1687
1688 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1689
1690 /*
1691 * Validate configuration.
1692 */
1693 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0" "CableConnected\0" "LineSpeed\0"))
1694 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1695 N_("Invalid configuration for VirtioNet device"));
1696
1697 /* Get config params */
1698 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", pState->config.mac.au8,
1699 sizeof(pState->config.mac.au8));
1700 if (RT_FAILURE(rc))
1701 return PDMDEV_SET_ERROR(pDevIns, rc,
1702 N_("Configuration error: Failed to get MAC address"));
1703 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pState->fCableConnected);
1704 if (RT_FAILURE(rc))
1705 return PDMDEV_SET_ERROR(pDevIns, rc,
1706 N_("Configuration error: Failed to get the value of 'CableConnected'"));
1707
1708 /* Initialize state structure */
1709 pState->fLocked = false;
1710 pState->u32PktNo = 1;
1711
1712 /* Interfaces */
1713 pState->INetworkPort.pfnWaitReceiveAvail = vnetWaitReceiveAvail;
1714 pState->INetworkPort.pfnReceive = vnetReceive;
1715 pState->INetworkConfig.pfnGetMac = vnetGetMac;
1716 pState->INetworkConfig.pfnGetLinkState = vnetGetLinkState;
1717 pState->INetworkConfig.pfnSetLinkState = vnetSetLinkState;
1718
1719 /* Register save/restore state handlers. */
1720 // TODO:
1721 /*
1722 rc = PDMDevHlpSSMRegisterEx(pDevIns, VVNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
1723 NULL, NULL, NULL,
1724 NULL, vnetSaveExec, NULL,
1725 NULL, vnetLoadExec, vnetLoadDone);
1726 if (RT_FAILURE(rc))
1727 return rc;*/
1728
1729 /* Create the RX notifier signaller. */
1730 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
1731 vnetCanRxQueueConsumer, true, "VNet-Rcv", &pState->pCanRxQueueR3);
1732 if (RT_FAILURE(rc))
1733 return rc;
1734 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
1735 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1736
1737 /* Create Link Up Timer */
1738 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetLinkUpTimer, pState,
1739 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
1740 "VirtioNet Link Up Timer", &pState->pLinkUpTimer);
1741 if (RT_FAILURE(rc))
1742 return rc;
1743
1744 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1745 if (RT_SUCCESS(rc))
1746 {
1747 if (rc == VINF_NAT_DNS)
1748 {
1749 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1750 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1751 }
1752 pState->pDrv = (PPDMINETWORKCONNECTOR)
1753 pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
1754 if (!pState->pDrv)
1755 {
1756 AssertMsgFailed(("%s Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
1757 return VERR_PDM_MISSING_INTERFACE_BELOW;
1758 }
1759 }
1760 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1761 {
1762 Log(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
1763 }
1764 else
1765 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
1766
1767 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
1768 if (RT_FAILURE(rc))
1769 return rc;
1770
1771 vnetReset(pState);
1772
1773 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
1774 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
1775#if defined(VBOX_WITH_STATISTICS)
1776 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
1777 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
1778 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
1779 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
1780 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
1781#endif /* VBOX_WITH_STATISTICS */
1782
1783 return VINF_SUCCESS;
1784}
1785
1786/**
1787 * Destruct a device instance.
1788 *
1789 * We need to free non-VM resources only.
1790 *
1791 * @returns VBox status.
1792 * @param pDevIns The device instance data.
1793 * @thread EMT
1794 */
1795static DECLCALLBACK(int) vnetDestruct(PPDMDEVINS pDevIns)
1796{
1797 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1798
1799 Log(("%s Destroying instance\n", INSTANCE(pState)));
1800 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1801 {
1802 RTSemEventSignal(pState->hEventMoreRxDescAvail);
1803 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
1804 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1805 }
1806
1807 return vpciDestruct(&pState->VPCI);
1808}
1809
1810/**
1811 * Device relocation callback.
1812 *
1813 * When this callback is called the device instance data, and if the
1814 * device have a GC component, is being relocated, or/and the selectors
1815 * have been changed. The device must use the chance to perform the
1816 * necessary pointer relocations and data updates.
1817 *
1818 * Before the GC code is executed the first time, this function will be
1819 * called with a 0 delta so GC pointer calculations can be one in one place.
1820 *
1821 * @param pDevIns Pointer to the device instance.
1822 * @param offDelta The relocation delta relative to the old location.
1823 *
1824 * @remark A relocation CANNOT fail.
1825 */
1826static DECLCALLBACK(void) vnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1827{
1828 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1829 vpciRelocate(pDevIns, offDelta);
1830 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1831 // TBD
1832}
1833
1834/**
1835 * @copydoc FNPDMDEVSUSPEND
1836 */
1837static DECLCALLBACK(void) vnetSuspend(PPDMDEVINS pDevIns)
1838{
1839 /* Poke thread waiting for buffer space. */
1840 vnetWakeupReceive(pDevIns);
1841}
1842
1843
1844#ifdef VBOX_DYNAMIC_NET_ATTACH
1845/**
1846 * Detach notification.
1847 *
1848 * One port on the network card has been disconnected from the network.
1849 *
1850 * @param pDevIns The device instance.
1851 * @param iLUN The logical unit which is being detached.
1852 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1853 */
1854static DECLCALLBACK(void) vnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1855{
1856 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1857 Log(("%s vnetDetach:\n", INSTANCE(pState)));
1858
1859 AssertLogRelReturnVoid(iLUN == 0);
1860
1861 vpciCsEnter(&pState->VPCI, VERR_SEM_BUSY);
1862
1863 /*
1864 * Zero some important members.
1865 */
1866 pState->pDrvBase = NULL;
1867 pState->pDrv = NULL;
1868
1869 vpciCsLeave(&pState->VPCI);
1870}
1871
1872
1873/**
1874 * Attach the Network attachment.
1875 *
1876 * One port on the network card has been connected to a network.
1877 *
1878 * @returns VBox status code.
1879 * @param pDevIns The device instance.
1880 * @param iLUN The logical unit which is being attached.
1881 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1882 *
1883 * @remarks This code path is not used during construction.
1884 */
1885static DECLCALLBACK(int) vnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1886{
1887 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1888 LogFlow(("%s vnetAttach:\n", INSTANCE(pState)));
1889
1890 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
1891
1892 vpciCsEnter(&pState->VPCI, VERR_SEM_BUSY);
1893
1894 /*
1895 * Attach the driver.
1896 */
1897 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1898 if (RT_SUCCESS(rc))
1899 {
1900 if (rc == VINF_NAT_DNS)
1901 {
1902#ifdef RT_OS_LINUX
1903 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1904 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1905#else
1906 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1907 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1908#endif
1909 }
1910 pState->pDrv = (PPDMINETWORKCONNECTOR)pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
1911 if (!pState->pDrv)
1912 {
1913 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
1914 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
1915 }
1916 }
1917 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1918 Log(("%s No attached driver!\n", INSTANCE(pState)));
1919
1920
1921 /*
1922 * Temporary set the link down if it was up so that the guest
1923 * will know that we have change the configuration of the
1924 * network card
1925 */
1926 if ((STATUS & VNET_S_LINK_UP) && RT_SUCCESS(rc))
1927 {
1928 STATUS &= ~VNET_S_LINK_UP;
1929 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1930 /* Restore the link back in 5 seconds. */
1931 vpciArmTimer(&pState->VPCI, pState->pLinkUpTimer, 5000000);
1932 }
1933
1934 vpciCsLeave(&pState->VPCI);
1935 return rc;
1936
1937}
1938#endif /* VBOX_DYNAMIC_NET_ATTACH */
1939
1940
1941/**
1942 * @copydoc FNPDMDEVPOWEROFF
1943 */
1944static DECLCALLBACK(void) vnetPowerOff(PPDMDEVINS pDevIns)
1945{
1946 /* Poke thread waiting for buffer space. */
1947 vnetWakeupReceive(pDevIns);
1948}
1949
1950/**
1951 * The device registration structure.
1952 */
1953const PDMDEVREG g_DeviceVirtioNet =
1954{
1955 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
1956 PDM_DEVREG_VERSION,
1957 /* Device name. */
1958 "virtio-net",
1959 /* Name of guest context module (no path).
1960 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
1961 "VBoxDDGC.gc",
1962 /* Name of ring-0 module (no path).
1963 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
1964 "VBoxDDR0.r0",
1965 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
1966 * remain unchanged from registration till VM destruction. */
1967 "Virtio Ethernet.\n",
1968
1969 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
1970 PDM_DEVREG_FLAGS_DEFAULT_BITS, // | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1971 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
1972 PDM_DEVREG_CLASS_NETWORK,
1973 /* Maximum number of instances (per VM). */
1974 8,
1975 /* Size of the instance data. */
1976 sizeof(VNETSTATE),
1977
1978 /* Construct instance - required. */
1979 vnetConstruct,
1980 /* Destruct instance - optional. */
1981 vnetDestruct,
1982 /* Relocation command - optional. */
1983 vnetRelocate,
1984 /* I/O Control interface - optional. */
1985 NULL,
1986 /* Power on notification - optional. */
1987 NULL,
1988 /* Reset notification - optional. */
1989 NULL,
1990 /* Suspend notification - optional. */
1991 vnetSuspend,
1992 /* Resume notification - optional. */
1993 NULL,
1994#ifdef VBOX_DYNAMIC_NET_ATTACH
1995 /* Attach command - optional. */
1996 vnetAttach,
1997 /* Detach notification - optional. */
1998 vnetDetach,
1999#else /* !VBOX_DYNAMIC_NET_ATTACH */
2000 /* Attach command - optional. */
2001 NULL,
2002 /* Detach notification - optional. */
2003 NULL,
2004#endif /* !VBOX_DYNAMIC_NET_ATTACH */
2005 /* Query a LUN base interface - optional. */
2006 NULL,
2007 /* Init complete notification - optional. */
2008 NULL,
2009 /* Power off notification - optional. */
2010 vnetPowerOff,
2011 /* pfnSoftReset */
2012 NULL,
2013 /* u32VersionEnd */
2014 PDM_DEVREG_VERSION
2015};
2016
2017#endif /* IN_RING3 */
2018#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2019
Note: See TracBrowser for help on using the repository browser.

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