VirtualBox

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

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

Virtio: small optimization (static TX buffer)

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