VirtualBox

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

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

Main,Misc Devices: _LS VMSTATEs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.2 KB
Line 
1/* $Id: DevVirtioNet.cpp 24191 2009-10-30 14:11:59Z 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#if 0
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}
1375
1376#ifdef IN_RING3
1377/**
1378 * Wakeup the RX thread.
1379 */
1380static void vnetWakeupReceive(PPDMDEVINS pDevIns)
1381{
1382 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE *);
1383 if ( pState->fMaybeOutOfSpace
1384 && pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1385 {
1386 STAM_COUNTER_INC(&pState->StatRxOverflowWakeup);
1387 Log(("%s Waking up Out-of-RX-space semaphore\n", INSTANCE(pState)));
1388 RTSemEventSignal(pState->hEventMoreRxDescAvail);
1389 }
1390}
1391
1392/**
1393 * Link Up Timer handler.
1394 *
1395 * @param pDevIns Pointer to device instance structure.
1396 * @param pTimer Pointer to the timer.
1397 * @param pvUser NULL.
1398 * @thread EMT
1399 */
1400static DECLCALLBACK(void) vnetLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1401{
1402 VNETSTATE *pState = (VNETSTATE *)pvUser;
1403
1404 STATUS |= VNET_S_LINK_UP;
1405 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1406 vnetWakeupReceive(pDevIns);
1407}
1408
1409
1410
1411
1412/**
1413 * Handler for the wakeup signaller queue.
1414 */
1415static DECLCALLBACK(bool) vnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1416{
1417 vnetWakeupReceive(pDevIns);
1418 return true;
1419}
1420
1421#endif /* IN_RING3 */
1422
1423/**
1424 * This function is called when the driver becomes ready.
1425 *
1426 * @param pState The device state structure.
1427 */
1428PDMBOTHCBDECL(void) vnetReady(void *pvState)
1429{
1430 VNETSTATE *pState = (VNETSTATE*)pvState;
1431 Log(("%s Driver became ready, waking up RX thread...\n", INSTANCE(pState)));
1432#ifdef IN_RING3
1433 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
1434#else
1435 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pCanRxQueue));
1436 if (pItem)
1437 PDMQueueInsert(pState->CTX_SUFF(pCanRxQueue), pItem);
1438#endif
1439}
1440
1441
1442#ifdef IN_RING3
1443
1444/**
1445 * Check if the device can receive data now.
1446 * This must be called before the pfnRecieve() method is called.
1447 *
1448 * @remarks As a side effect this function enables queue notification
1449 * if it cannot receive because the queue is empty.
1450 * It disables notification if it can receive.
1451 *
1452 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
1453 * @param pInterface Pointer to the interface structure containing the called function pointer.
1454 * @thread RX
1455 */
1456static int vnetCanReceive(VNETSTATE *pState)
1457{
1458 int rc = vpciCsEnter(&pState->VPCI, VERR_SEM_BUSY);
1459 LogFlow(("%s vnetCanReceive\n", INSTANCE(pState)));
1460 if (!(pState->VPCI.uStatus & VPCI_STATUS_DRV_OK))
1461 rc = VERR_NET_NO_BUFFER_SPACE;
1462 else if (!vqueueIsReady(&pState->VPCI, pState->pRxQueue))
1463 rc = VERR_NET_NO_BUFFER_SPACE;
1464 else if (vqueueIsEmpty(&pState->VPCI, pState->pRxQueue))
1465 {
1466 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, true);
1467 rc = VERR_NET_NO_BUFFER_SPACE;
1468 }
1469 else
1470 {
1471 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, false);
1472 rc = VINF_SUCCESS;
1473 }
1474
1475 LogFlow(("%s vnetCanReceive -> %Vrc\n", INSTANCE(pState), rc));
1476 vpciCsLeave(&pState->VPCI);
1477 return rc;
1478}
1479
1480static DECLCALLBACK(int) vnetWaitReceiveAvail(PPDMINETWORKPORT pInterface, unsigned cMillies)
1481{
1482 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
1483 LogFlow(("%s vnetWaitReceiveAvail(cMillies=%u)\n", INSTANCE(pState), cMillies));
1484 int rc = vnetCanReceive(pState);
1485
1486 if (RT_SUCCESS(rc))
1487 return VINF_SUCCESS;
1488 if (RT_UNLIKELY(cMillies == 0))
1489 return VERR_NET_NO_BUFFER_SPACE;
1490
1491 rc = VERR_INTERRUPTED;
1492 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, true);
1493 STAM_PROFILE_START(&pState->StatRxOverflow, a);
1494
1495 VMSTATE enmVMState;
1496 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
1497 || enmVMState == VMSTATE_RUNNING_LS))
1498 {
1499 int rc2 = vnetCanReceive(pState);
1500 if (RT_SUCCESS(rc2))
1501 {
1502 rc = VINF_SUCCESS;
1503 break;
1504 }
1505 Log(("%s vnetWaitReceiveAvail: waiting cMillies=%u...\n",
1506 INSTANCE(pState), cMillies));
1507 RTSemEventWait(pState->hEventMoreRxDescAvail, cMillies);
1508 }
1509 STAM_PROFILE_STOP(&pState->StatRxOverflow, a);
1510 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, false);
1511
1512 LogFlow(("%s vnetWaitReceiveAvail -> %d\n", INSTANCE(pState), rc));
1513 return rc;
1514}
1515
1516
1517/**
1518 * Provides interfaces to the driver.
1519 *
1520 * @returns Pointer to interface. NULL if the interface is not supported.
1521 * @param pInterface Pointer to this interface structure.
1522 * @param enmInterface The requested interface identification.
1523 * @thread EMT
1524 */
1525static DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
1526{
1527 VNETSTATE *pState = IFACE_TO_STATE(pInterface, VPCI.IBase);
1528 Assert(&pState->VPCI.IBase == pInterface);
1529 switch (enmInterface)
1530 {
1531 case PDMINTERFACE_NETWORK_PORT:
1532 return &pState->INetworkPort;
1533 case PDMINTERFACE_NETWORK_CONFIG:
1534 return &pState->INetworkConfig;
1535 default:
1536 return vpciQueryInterface(pInterface, enmInterface);
1537 }
1538}
1539
1540/**
1541 * Determines if the packet is to be delivered to upper layer. The following
1542 * filters supported:
1543 * - Exact Unicast/Multicast
1544 * - Promiscuous Unicast/Multicast
1545 * - Multicast
1546 * - VLAN
1547 *
1548 * @returns true if packet is intended for this node.
1549 * @param pState Pointer to the state structure.
1550 * @param pvBuf The ethernet packet.
1551 * @param cb Number of bytes available in the packet.
1552 */
1553static bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
1554{
1555 return true; // TODO: Implement!
1556}
1557
1558/**
1559 * Pad and store received packet.
1560 *
1561 * @remarks Make sure that the packet appears to upper layer as one coming
1562 * from real Ethernet: pad it and insert FCS.
1563 *
1564 * @returns VBox status code.
1565 * @param pState The device state structure.
1566 * @param pvBuf The available data.
1567 * @param cb Number of bytes available in the buffer.
1568 * @thread RX
1569 */
1570static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
1571{
1572 VNETHDR hdr;
1573
1574 hdr.u8Flags = 0;
1575 hdr.u8GSOType = VNETHDR_GSO_NONE;
1576
1577 unsigned int uOffset = 0;
1578 for (unsigned int nElem = 0; uOffset < cb; nElem++)
1579 {
1580 VQUEUEELEM elem;
1581 unsigned int nSeg = 0, uElemSize = 0;
1582
1583 if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
1584 {
1585 Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
1586 return VERR_INTERNAL_ERROR;
1587 }
1588
1589 if (elem.nIn < 1)
1590 {
1591 Log(("%s vnetHandleRxPacket: No writable descriptors in receive queue!\n", INSTANCE(pState)));
1592 return VERR_INTERNAL_ERROR;
1593 }
1594
1595 if (nElem == 0)
1596 {
1597 /* The very first segment of the very first element gets the header. */
1598 if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
1599 {
1600 Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
1601 return VERR_INTERNAL_ERROR;
1602 }
1603
1604 elem.aSegsIn[nSeg++].pv = &hdr;
1605 uElemSize += sizeof(VNETHDR);
1606 }
1607
1608 while (nSeg < elem.nIn && uOffset < cb)
1609 {
1610 unsigned int uSize = RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
1611 elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
1612 uOffset += uSize;
1613 uElemSize += uSize;
1614 }
1615 vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
1616 }
1617 vqueueSync(&pState->VPCI, pState->pRxQueue);
1618
1619 return VINF_SUCCESS;
1620}
1621
1622/**
1623 * Receive data from the network.
1624 *
1625 * @returns VBox status code.
1626 * @param pInterface Pointer to the interface structure containing the called function pointer.
1627 * @param pvBuf The available data.
1628 * @param cb Number of bytes available in the buffer.
1629 * @thread RX
1630 */
1631static DECLCALLBACK(int) vnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
1632{
1633 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkPort);
1634 int rc = VINF_SUCCESS;
1635
1636 Log2(("%s vnetReceive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
1637 rc = vnetCanReceive(pState);
1638 if (RT_FAILURE(rc))
1639 return rc;
1640
1641 vpciSetReadLed(&pState->VPCI, true);
1642 if (vnetAddressFilter(pState, pvBuf, cb))
1643 {
1644 rc = vnetHandleRxPacket(pState, pvBuf, cb);
1645 }
1646 vpciSetReadLed(&pState->VPCI, false);
1647
1648 return rc;
1649}
1650
1651/**
1652 * Gets the current Media Access Control (MAC) address.
1653 *
1654 * @returns VBox status code.
1655 * @param pInterface Pointer to the interface structure containing the called function pointer.
1656 * @param pMac Where to store the MAC address.
1657 * @thread EMT
1658 */
1659static DECLCALLBACK(int) vnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
1660{
1661 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1662 memcpy(pMac, pState->config.mac.au8, sizeof(RTMAC));
1663 return VINF_SUCCESS;
1664}
1665
1666/**
1667 * Gets the new link state.
1668 *
1669 * @returns The current link state.
1670 * @param pInterface Pointer to the interface structure containing the called function pointer.
1671 * @thread EMT
1672 */
1673static DECLCALLBACK(PDMNETWORKLINKSTATE) vnetGetLinkState(PPDMINETWORKCONFIG pInterface)
1674{
1675 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1676 if (STATUS & VNET_S_LINK_UP)
1677 return PDMNETWORKLINKSTATE_UP;
1678 return PDMNETWORKLINKSTATE_DOWN;
1679}
1680
1681
1682/**
1683 * Sets the new link state.
1684 *
1685 * @returns VBox status code.
1686 * @param pInterface Pointer to the interface structure containing the called function pointer.
1687 * @param enmState The new link state
1688 */
1689static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
1690{
1691 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1692 bool fOldUp = !!(STATUS & VNET_S_LINK_UP);
1693 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
1694
1695 if (fNewUp != fOldUp)
1696 {
1697 if (fNewUp)
1698 {
1699 Log(("%s Link is up\n", INSTANCE(pState)));
1700 STATUS |= VNET_S_LINK_UP;
1701 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1702 }
1703 else
1704 {
1705 Log(("%s Link is down\n", INSTANCE(pState)));
1706 STATUS &= ~VNET_S_LINK_UP;
1707 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1708 }
1709 if (pState->pDrv)
1710 pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
1711 }
1712 return VINF_SUCCESS;
1713}
1714
1715static DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
1716{
1717 VNETSTATE *pState = (VNETSTATE*)pvState;
1718 Log(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pState)));
1719 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
1720}
1721
1722static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
1723{
1724 VNETSTATE *pState = (VNETSTATE*)pvState;
1725 if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
1726 {
1727 Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
1728 INSTANCE(pState), pState->VPCI.uStatus));
1729 return;
1730 }
1731
1732 vpciSetWriteLed(&pState->VPCI, true);
1733
1734 VQUEUEELEM elem;
1735 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1736 {
1737 unsigned int uOffset = 0;
1738 if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
1739 {
1740 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
1741 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
1742 vqueueElemFree(&elem);
1743 break; /* For now we simply ignore the header, but it must be there anyway! */
1744 }
1745 else
1746 {
1747 uint8_t *pFrame = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
1748 if (!pFrame)
1749 {
1750 Log(("%s vnetQueueTransmit: Failed to allocate %u bytes.\n",
1751 INSTANCE(pState), VNET_MAX_FRAME_SIZE));
1752 vqueueElemFree(&elem);
1753 break; /* For now we simply ignore the header, but it must be there anyway! */
1754 }
1755
1756 /* Assemble a complete frame. */
1757 for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
1758 {
1759 unsigned int uSize = elem.aSegsOut[i].cb;
1760 if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
1761 {
1762 Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
1763 uSize = VNET_MAX_FRAME_SIZE - uOffset;
1764 }
1765 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
1766 pFrame + uOffset, uSize);
1767 uOffset += uSize;
1768 }
1769 STAM_PROFILE_ADV_START(&pState->StatTransmitSend, a);
1770 int rc = pState->pDrv->pfnSend(pState->pDrv, pFrame, uOffset);
1771 STAM_PROFILE_ADV_STOP(&pState->StatTransmitSend, a);
1772 RTMemFree(pFrame);
1773 }
1774 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
1775 vqueueSync(&pState->VPCI, pQueue);
1776 }
1777 vpciSetWriteLed(&pState->VPCI, false);
1778}
1779
1780static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
1781{
1782 VNETSTATE *pState = (VNETSTATE*)pvState;
1783 Log(("%s Pending control message\n", INSTANCE(pState)));
1784}
1785
1786/**
1787 * Saves the configuration.
1788 *
1789 * @param pState The VNET state.
1790 * @param pSSM The handle to the saved state.
1791 */
1792static void vnetSaveConfig(VNETSTATE *pState, PSSMHANDLE pSSM)
1793{
1794 SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
1795}
1796
1797/**
1798 * Live save - save basic configuration.
1799 *
1800 * @returns VBox status code.
1801 * @param pDevIns The device instance.
1802 * @param pSSM The handle to the saved state.
1803 * @param uPass
1804 */
1805static DECLCALLBACK(int) vnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1806{
1807 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1808 vnetSaveConfig(pState, pSSM);
1809 return VINF_SSM_DONT_CALL_AGAIN;
1810}
1811
1812/**
1813 * Prepares for state saving.
1814 *
1815 * @returns VBox status code.
1816 * @param pDevIns The device instance.
1817 * @param pSSM The handle to the saved state.
1818 */
1819static DECLCALLBACK(int) vnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1820{
1821 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1822
1823 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1824 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1825 return rc;
1826 vnetCsLeave(pState);
1827 return VINF_SUCCESS;
1828}
1829
1830/**
1831 * Saves the state of device.
1832 *
1833 * @returns VBox status code.
1834 * @param pDevIns The device instance.
1835 * @param pSSM The handle to the saved state.
1836 */
1837static DECLCALLBACK(int) vnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1838{
1839 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1840
1841 /* Save config first */
1842 vnetSaveConfig(pState, pSSM);
1843
1844 /* Save the common part */
1845 int rc = vpciSaveExec(&pState->VPCI, pSSM);
1846 AssertRCReturn(rc, rc);
1847 /* Save device-specific part */
1848 rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1849 AssertRCReturn(rc, rc);
1850 Log(("%s State has been saved\n", INSTANCE(pState)));
1851 return VINF_SUCCESS;
1852}
1853
1854
1855/**
1856 * Serializes the receive thread, it may be working inside the critsect.
1857 *
1858 * @returns VBox status code.
1859 * @param pDevIns The device instance.
1860 * @param pSSM The handle to the saved state.
1861 */
1862static DECLCALLBACK(int) vnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1863{
1864 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1865
1866 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1867 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1868 return rc;
1869 vnetCsLeave(pState);
1870 return VINF_SUCCESS;
1871}
1872
1873/* Takes down the link temporarily if it's current status is up.
1874 *
1875 * This is used during restore and when replumbing the network link.
1876 *
1877 * The temporary link outage is supposed to indicate to the OS that all network
1878 * connections have been lost and that it for instance is appropriate to
1879 * renegotiate any DHCP lease.
1880 *
1881 * @param pThis The PCNet instance data.
1882 */
1883static void vnetTempLinkDown(PVNETSTATE pState)
1884{
1885 if (STATUS & VNET_S_LINK_UP)
1886 {
1887 STATUS &= ~VNET_S_LINK_UP;
1888 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1889 /* Restore the link back in 5 seconds. */
1890 int rc = TMTimerSetMillies(pState->pLinkUpTimer, 5000);
1891 AssertRC(rc);
1892 }
1893}
1894
1895
1896/**
1897 * Restore previously saved state of device.
1898 *
1899 * @returns VBox status code.
1900 * @param pDevIns The device instance.
1901 * @param pSSM The handle to the saved state.
1902 * @param uVersion The data unit version number.
1903 * @param uPass The data pass.
1904 */
1905static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1906{
1907 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1908 int rc;
1909
1910 /* config checks */
1911 RTMAC macConfigured;
1912 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
1913 AssertRCReturn(rc, rc);
1914 if ( memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
1915 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
1916 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
1917
1918 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass);
1919 AssertRCReturn(rc, rc);
1920
1921 if (uPass == SSM_PASS_FINAL)
1922 {
1923 rc = SSMR3GetMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1924 AssertRCReturn(rc, rc);
1925 /* Indicate link down to the guest OS that all network connections have
1926 been lost, unless we've been teleported here. */
1927 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
1928 vnetTempLinkDown(pState);
1929 }
1930
1931 return rc;
1932}
1933
1934/**
1935 * Construct a device instance for a VM.
1936 *
1937 * @returns VBox status.
1938 * @param pDevIns The device instance data.
1939 * If the registration structure is needed, pDevIns->pDevReg points to it.
1940 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1941 * The device number is also found in pDevIns->iInstance, but since it's
1942 * likely to be freqently used PDM passes it as parameter.
1943 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1944 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1945 * iInstance it's expected to be used a bit in this function.
1946 * @thread EMT
1947 */
1948static DECLCALLBACK(int) vnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1949{
1950 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1951 int rc;
1952
1953 /* Initialize PCI part first. */
1954 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface;
1955 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance, VIRTIO_NET_ID, sizeof(VNetPCIConfig));
1956 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive);
1957 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit);
1958 pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16, vnetQueueControl);
1959
1960 Log(("%s Constructing new instance\n", INSTANCE(pState)));
1961
1962 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1963
1964 /*
1965 * Validate configuration.
1966 */
1967 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0" "CableConnected\0" "LineSpeed\0"))
1968 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1969 N_("Invalid configuration for VirtioNet device"));
1970
1971 /* Get config params */
1972 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", pState->macConfigured.au8,
1973 sizeof(pState->macConfigured));
1974 if (RT_FAILURE(rc))
1975 return PDMDEV_SET_ERROR(pDevIns, rc,
1976 N_("Configuration error: Failed to get MAC address"));
1977 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pState->fCableConnected);
1978 if (RT_FAILURE(rc))
1979 return PDMDEV_SET_ERROR(pDevIns, rc,
1980 N_("Configuration error: Failed to get the value of 'CableConnected'"));
1981
1982 /* Initialize PCI config space */
1983 memcpy(pState->config.mac.au8, pState->macConfigured.au8, sizeof(pState->config.mac.au8));
1984 pState->config.uStatus = 0;
1985
1986 /* Initialize state structure */
1987 pState->fLocked = false;
1988 pState->u32PktNo = 1;
1989
1990 /* Interfaces */
1991 pState->INetworkPort.pfnWaitReceiveAvail = vnetWaitReceiveAvail;
1992 pState->INetworkPort.pfnReceive = vnetReceive;
1993 pState->INetworkConfig.pfnGetMac = vnetGetMac;
1994 pState->INetworkConfig.pfnGetLinkState = vnetGetLinkState;
1995 pState->INetworkConfig.pfnSetLinkState = vnetSetLinkState;
1996
1997 /* Register save/restore state handlers. */
1998 rc = PDMDevHlpSSMRegisterEx(pDevIns, VNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
1999 NULL, vnetLiveExec, NULL,
2000 vnetSavePrep, vnetSaveExec, NULL,
2001 vnetLoadPrep, vnetLoadExec, NULL);
2002 if (RT_FAILURE(rc))
2003 return rc;
2004
2005 /* Create the RX notifier signaller. */
2006 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
2007 vnetCanRxQueueConsumer, true, "VNet-Rcv", &pState->pCanRxQueueR3);
2008 if (RT_FAILURE(rc))
2009 return rc;
2010 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
2011 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
2012
2013 /* Create Link Up Timer */
2014 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetLinkUpTimer, pState,
2015 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
2016 "VirtioNet Link Up Timer", &pState->pLinkUpTimer);
2017 if (RT_FAILURE(rc))
2018 return rc;
2019
2020 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
2021 if (RT_SUCCESS(rc))
2022 {
2023 if (rc == VINF_NAT_DNS)
2024 {
2025 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2026 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"));
2027 }
2028 pState->pDrv = (PPDMINETWORKCONNECTOR)
2029 pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
2030 if (!pState->pDrv)
2031 {
2032 AssertMsgFailed(("%s Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
2033 return VERR_PDM_MISSING_INTERFACE_BELOW;
2034 }
2035 }
2036 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2037 {
2038 Log(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
2039 }
2040 else
2041 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
2042
2043 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
2044 if (RT_FAILURE(rc))
2045 return rc;
2046
2047 vnetReset(pState);
2048
2049 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
2050 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
2051#if defined(VBOX_WITH_STATISTICS)
2052 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
2053 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
2054 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
2055 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
2056 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
2057#endif /* VBOX_WITH_STATISTICS */
2058
2059 return VINF_SUCCESS;
2060}
2061
2062/**
2063 * Destruct a device instance.
2064 *
2065 * We need to free non-VM resources only.
2066 *
2067 * @returns VBox status.
2068 * @param pDevIns The device instance data.
2069 * @thread EMT
2070 */
2071static DECLCALLBACK(int) vnetDestruct(PPDMDEVINS pDevIns)
2072{
2073 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2074
2075 Log(("%s Destroying instance\n", INSTANCE(pState)));
2076 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
2077 {
2078 RTSemEventSignal(pState->hEventMoreRxDescAvail);
2079 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
2080 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
2081 }
2082
2083 return vpciDestruct(&pState->VPCI);
2084}
2085
2086/**
2087 * Device relocation callback.
2088 *
2089 * When this callback is called the device instance data, and if the
2090 * device have a GC component, is being relocated, or/and the selectors
2091 * have been changed. The device must use the chance to perform the
2092 * necessary pointer relocations and data updates.
2093 *
2094 * Before the GC code is executed the first time, this function will be
2095 * called with a 0 delta so GC pointer calculations can be one in one place.
2096 *
2097 * @param pDevIns Pointer to the device instance.
2098 * @param offDelta The relocation delta relative to the old location.
2099 *
2100 * @remark A relocation CANNOT fail.
2101 */
2102static DECLCALLBACK(void) vnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2103{
2104 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2105 vpciRelocate(pDevIns, offDelta);
2106 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
2107 // TBD
2108}
2109
2110/**
2111 * @copydoc FNPDMDEVSUSPEND
2112 */
2113static DECLCALLBACK(void) vnetSuspend(PPDMDEVINS pDevIns)
2114{
2115 /* Poke thread waiting for buffer space. */
2116 vnetWakeupReceive(pDevIns);
2117}
2118
2119
2120#ifdef VBOX_DYNAMIC_NET_ATTACH
2121/**
2122 * Detach notification.
2123 *
2124 * One port on the network card has been disconnected from the network.
2125 *
2126 * @param pDevIns The device instance.
2127 * @param iLUN The logical unit which is being detached.
2128 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2129 */
2130static DECLCALLBACK(void) vnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2131{
2132 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2133 Log(("%s vnetDetach:\n", INSTANCE(pState)));
2134
2135 AssertLogRelReturnVoid(iLUN == 0);
2136
2137 vpciCsEnter(&pState->VPCI, VERR_SEM_BUSY);
2138
2139 /*
2140 * Zero some important members.
2141 */
2142 pState->pDrvBase = NULL;
2143 pState->pDrv = NULL;
2144
2145 vpciCsLeave(&pState->VPCI);
2146}
2147
2148
2149/**
2150 * Attach the Network attachment.
2151 *
2152 * One port on the network card has been connected to a network.
2153 *
2154 * @returns VBox status code.
2155 * @param pDevIns The device instance.
2156 * @param iLUN The logical unit which is being attached.
2157 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2158 *
2159 * @remarks This code path is not used during construction.
2160 */
2161static DECLCALLBACK(int) vnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2162{
2163 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2164 LogFlow(("%s vnetAttach:\n", INSTANCE(pState)));
2165
2166 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
2167
2168 vpciCsEnter(&pState->VPCI, VERR_SEM_BUSY);
2169
2170 /*
2171 * Attach the driver.
2172 */
2173 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
2174 if (RT_SUCCESS(rc))
2175 {
2176 if (rc == VINF_NAT_DNS)
2177 {
2178#ifdef RT_OS_LINUX
2179 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2180 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"));
2181#else
2182 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2183 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"));
2184#endif
2185 }
2186 pState->pDrv = (PPDMINETWORKCONNECTOR)pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
2187 if (!pState->pDrv)
2188 {
2189 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
2190 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
2191 }
2192 }
2193 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2194 Log(("%s No attached driver!\n", INSTANCE(pState)));
2195
2196
2197 /*
2198 * Temporary set the link down if it was up so that the guest
2199 * will know that we have change the configuration of the
2200 * network card
2201 */
2202 if (RT_SUCCESS(rc))
2203 vnetTempLinkDown(pState);
2204
2205 vpciCsLeave(&pState->VPCI);
2206 return rc;
2207
2208}
2209#endif /* VBOX_DYNAMIC_NET_ATTACH */
2210
2211
2212/**
2213 * @copydoc FNPDMDEVPOWEROFF
2214 */
2215static DECLCALLBACK(void) vnetPowerOff(PPDMDEVINS pDevIns)
2216{
2217 /* Poke thread waiting for buffer space. */
2218 vnetWakeupReceive(pDevIns);
2219}
2220
2221/**
2222 * The device registration structure.
2223 */
2224const PDMDEVREG g_DeviceVirtioNet =
2225{
2226 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
2227 PDM_DEVREG_VERSION,
2228 /* Device name. */
2229 "virtio-net",
2230 /* Name of guest context module (no path).
2231 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
2232 "VBoxDDGC.gc",
2233 /* Name of ring-0 module (no path).
2234 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
2235 "VBoxDDR0.r0",
2236 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
2237 * remain unchanged from registration till VM destruction. */
2238 "Virtio Ethernet.\n",
2239
2240 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
2241 PDM_DEVREG_FLAGS_DEFAULT_BITS, // | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2242 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
2243 PDM_DEVREG_CLASS_NETWORK,
2244 /* Maximum number of instances (per VM). */
2245 8,
2246 /* Size of the instance data. */
2247 sizeof(VNETSTATE),
2248
2249 /* Construct instance - required. */
2250 vnetConstruct,
2251 /* Destruct instance - optional. */
2252 vnetDestruct,
2253 /* Relocation command - optional. */
2254 vnetRelocate,
2255 /* I/O Control interface - optional. */
2256 NULL,
2257 /* Power on notification - optional. */
2258 NULL,
2259 /* Reset notification - optional. */
2260 NULL,
2261 /* Suspend notification - optional. */
2262 vnetSuspend,
2263 /* Resume notification - optional. */
2264 NULL,
2265#ifdef VBOX_DYNAMIC_NET_ATTACH
2266 /* Attach command - optional. */
2267 vnetAttach,
2268 /* Detach notification - optional. */
2269 vnetDetach,
2270#else /* !VBOX_DYNAMIC_NET_ATTACH */
2271 /* Attach command - optional. */
2272 NULL,
2273 /* Detach notification - optional. */
2274 NULL,
2275#endif /* !VBOX_DYNAMIC_NET_ATTACH */
2276 /* Query a LUN base interface - optional. */
2277 NULL,
2278 /* Init complete notification - optional. */
2279 NULL,
2280 /* Power off notification - optional. */
2281 vnetPowerOff,
2282 /* pfnSoftReset */
2283 NULL,
2284 /* u32VersionEnd */
2285 PDM_DEVREG_VERSION
2286};
2287
2288#endif /* IN_RING3 */
2289#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2290
Note: See TracBrowser for help on using the repository browser.

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