VirtualBox

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

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

VirtIO-net: update the counters

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