VirtualBox

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

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

#3987: Virtio: TX delay timer for batching, fixed assertion on state loading, minor GC improvements.

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