VirtualBox

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

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

#3987: Virtio: Fixed the status reporting required by recent kernels (virtio drivers).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.4 KB
Line 
1/* $Id: DevVirtioNet.cpp 24470 2009-11-06 17:56:31Z 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 }
1650 vpciSetReadLed(&pState->VPCI, false);
1651
1652 return rc;
1653}
1654
1655/**
1656 * Gets the current Media Access Control (MAC) address.
1657 *
1658 * @returns VBox status code.
1659 * @param pInterface Pointer to the interface structure containing the called function pointer.
1660 * @param pMac Where to store the MAC address.
1661 * @thread EMT
1662 */
1663static DECLCALLBACK(int) vnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
1664{
1665 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1666 memcpy(pMac, pState->config.mac.au8, sizeof(RTMAC));
1667 return VINF_SUCCESS;
1668}
1669
1670/**
1671 * Gets the new link state.
1672 *
1673 * @returns The current link state.
1674 * @param pInterface Pointer to the interface structure containing the called function pointer.
1675 * @thread EMT
1676 */
1677static DECLCALLBACK(PDMNETWORKLINKSTATE) vnetGetLinkState(PPDMINETWORKCONFIG pInterface)
1678{
1679 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1680 if (STATUS & VNET_S_LINK_UP)
1681 return PDMNETWORKLINKSTATE_UP;
1682 return PDMNETWORKLINKSTATE_DOWN;
1683}
1684
1685
1686/**
1687 * Sets the new link state.
1688 *
1689 * @returns VBox status code.
1690 * @param pInterface Pointer to the interface structure containing the called function pointer.
1691 * @param enmState The new link state
1692 */
1693static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
1694{
1695 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
1696 bool fOldUp = !!(STATUS & VNET_S_LINK_UP);
1697 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
1698
1699 if (fNewUp != fOldUp)
1700 {
1701 if (fNewUp)
1702 {
1703 Log(("%s Link is up\n", INSTANCE(pState)));
1704 STATUS |= VNET_S_LINK_UP;
1705 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1706 }
1707 else
1708 {
1709 Log(("%s Link is down\n", INSTANCE(pState)));
1710 STATUS &= ~VNET_S_LINK_UP;
1711 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1712 }
1713 if (pState->pDrv)
1714 pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
1715 }
1716 return VINF_SUCCESS;
1717}
1718
1719static DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
1720{
1721 VNETSTATE *pState = (VNETSTATE*)pvState;
1722 Log(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pState)));
1723 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
1724}
1725
1726static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
1727{
1728 VNETSTATE *pState = (VNETSTATE*)pvState;
1729 if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
1730 {
1731 Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
1732 INSTANCE(pState), pState->VPCI.uStatus));
1733 return;
1734 }
1735
1736 vpciSetWriteLed(&pState->VPCI, true);
1737
1738 VQUEUEELEM elem;
1739 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1740 {
1741 unsigned int uOffset = 0;
1742 if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
1743 {
1744 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
1745 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
1746 vqueueElemFree(&elem);
1747 break; /* For now we simply ignore the header, but it must be there anyway! */
1748 }
1749 else
1750 {
1751 uint8_t *pFrame = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
1752 if (!pFrame)
1753 {
1754 Log(("%s vnetQueueTransmit: Failed to allocate %u bytes.\n",
1755 INSTANCE(pState), VNET_MAX_FRAME_SIZE));
1756 vqueueElemFree(&elem);
1757 break; /* For now we simply ignore the header, but it must be there anyway! */
1758 }
1759
1760 /* Assemble a complete frame. */
1761 for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
1762 {
1763 unsigned int uSize = elem.aSegsOut[i].cb;
1764 if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
1765 {
1766 Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
1767 uSize = VNET_MAX_FRAME_SIZE - uOffset;
1768 }
1769 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
1770 pFrame + uOffset, uSize);
1771 uOffset += uSize;
1772 }
1773 STAM_PROFILE_ADV_START(&pState->StatTransmitSend, a);
1774 int rc = pState->pDrv->pfnSend(pState->pDrv, pFrame, uOffset);
1775 STAM_PROFILE_ADV_STOP(&pState->StatTransmitSend, a);
1776 RTMemFree(pFrame);
1777 }
1778 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
1779 vqueueSync(&pState->VPCI, pQueue);
1780 }
1781 vpciSetWriteLed(&pState->VPCI, false);
1782}
1783
1784static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
1785{
1786 VNETSTATE *pState = (VNETSTATE*)pvState;
1787 Log(("%s Pending control message\n", INSTANCE(pState)));
1788}
1789
1790/**
1791 * Saves the configuration.
1792 *
1793 * @param pState The VNET state.
1794 * @param pSSM The handle to the saved state.
1795 */
1796static void vnetSaveConfig(VNETSTATE *pState, PSSMHANDLE pSSM)
1797{
1798 SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
1799}
1800
1801/**
1802 * Live save - save basic configuration.
1803 *
1804 * @returns VBox status code.
1805 * @param pDevIns The device instance.
1806 * @param pSSM The handle to the saved state.
1807 * @param uPass
1808 */
1809static DECLCALLBACK(int) vnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1810{
1811 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1812 vnetSaveConfig(pState, pSSM);
1813 return VINF_SSM_DONT_CALL_AGAIN;
1814}
1815
1816/**
1817 * Prepares for state saving.
1818 *
1819 * @returns VBox status code.
1820 * @param pDevIns The device instance.
1821 * @param pSSM The handle to the saved state.
1822 */
1823static DECLCALLBACK(int) vnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1824{
1825 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1826
1827 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1828 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1829 return rc;
1830 vnetCsLeave(pState);
1831 return VINF_SUCCESS;
1832}
1833
1834/**
1835 * Saves the state of device.
1836 *
1837 * @returns VBox status code.
1838 * @param pDevIns The device instance.
1839 * @param pSSM The handle to the saved state.
1840 */
1841static DECLCALLBACK(int) vnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1842{
1843 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1844
1845 /* Save config first */
1846 vnetSaveConfig(pState, pSSM);
1847
1848 /* Save the common part */
1849 int rc = vpciSaveExec(&pState->VPCI, pSSM);
1850 AssertRCReturn(rc, rc);
1851 /* Save device-specific part */
1852 rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1853 AssertRCReturn(rc, rc);
1854 Log(("%s State has been saved\n", INSTANCE(pState)));
1855 return VINF_SUCCESS;
1856}
1857
1858
1859/**
1860 * Serializes the receive thread, it may be working inside the critsect.
1861 *
1862 * @returns VBox status code.
1863 * @param pDevIns The device instance.
1864 * @param pSSM The handle to the saved state.
1865 */
1866static DECLCALLBACK(int) vnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1867{
1868 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1869
1870 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1871 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1872 return rc;
1873 vnetCsLeave(pState);
1874 return VINF_SUCCESS;
1875}
1876
1877/* Takes down the link temporarily if it's current status is up.
1878 *
1879 * This is used during restore and when replumbing the network link.
1880 *
1881 * The temporary link outage is supposed to indicate to the OS that all network
1882 * connections have been lost and that it for instance is appropriate to
1883 * renegotiate any DHCP lease.
1884 *
1885 * @param pThis The PCNet instance data.
1886 */
1887static void vnetTempLinkDown(PVNETSTATE pState)
1888{
1889 if (STATUS & VNET_S_LINK_UP)
1890 {
1891 STATUS &= ~VNET_S_LINK_UP;
1892 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1893 /* Restore the link back in 5 seconds. */
1894 int rc = TMTimerSetMillies(pState->pLinkUpTimer, 5000);
1895 AssertRC(rc);
1896 }
1897}
1898
1899
1900/**
1901 * Restore previously saved state of device.
1902 *
1903 * @returns VBox status code.
1904 * @param pDevIns The device instance.
1905 * @param pSSM The handle to the saved state.
1906 * @param uVersion The data unit version number.
1907 * @param uPass The data pass.
1908 */
1909static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1910{
1911 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1912 int rc;
1913
1914 /* config checks */
1915 RTMAC macConfigured;
1916 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
1917 AssertRCReturn(rc, rc);
1918 if ( memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
1919 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
1920 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
1921
1922 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass);
1923 AssertRCReturn(rc, rc);
1924
1925 if (uPass == SSM_PASS_FINAL)
1926 {
1927 rc = SSMR3GetMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1928 AssertRCReturn(rc, rc);
1929 /* Indicate link down to the guest OS that all network connections have
1930 been lost, unless we've been teleported here. */
1931 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
1932 vnetTempLinkDown(pState);
1933 }
1934
1935 return rc;
1936}
1937
1938/**
1939 * Construct a device instance for a VM.
1940 *
1941 * @returns VBox status.
1942 * @param pDevIns The device instance data.
1943 * If the registration structure is needed, pDevIns->pDevReg points to it.
1944 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1945 * The device number is also found in pDevIns->iInstance, but since it's
1946 * likely to be freqently used PDM passes it as parameter.
1947 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1948 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1949 * iInstance it's expected to be used a bit in this function.
1950 * @thread EMT
1951 */
1952static DECLCALLBACK(int) vnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1953{
1954 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1955 int rc;
1956
1957 /* Initialize PCI part first. */
1958 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface;
1959 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance, VIRTIO_NET_ID, sizeof(VNetPCIConfig));
1960 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive);
1961 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit);
1962 pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16, vnetQueueControl);
1963
1964 Log(("%s Constructing new instance\n", INSTANCE(pState)));
1965
1966 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1967
1968 /*
1969 * Validate configuration.
1970 */
1971 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0" "CableConnected\0" "LineSpeed\0"))
1972 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1973 N_("Invalid configuration for VirtioNet device"));
1974
1975 /* Get config params */
1976 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", pState->macConfigured.au8,
1977 sizeof(pState->macConfigured));
1978 if (RT_FAILURE(rc))
1979 return PDMDEV_SET_ERROR(pDevIns, rc,
1980 N_("Configuration error: Failed to get MAC address"));
1981 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pState->fCableConnected);
1982 if (RT_FAILURE(rc))
1983 return PDMDEV_SET_ERROR(pDevIns, rc,
1984 N_("Configuration error: Failed to get the value of 'CableConnected'"));
1985
1986 /* Initialize PCI config space */
1987 memcpy(pState->config.mac.au8, pState->macConfigured.au8, sizeof(pState->config.mac.au8));
1988 pState->config.uStatus = 0;
1989
1990 /* Initialize state structure */
1991 pState->fLocked = false;
1992 pState->u32PktNo = 1;
1993
1994 /* Interfaces */
1995 pState->INetworkPort.pfnWaitReceiveAvail = vnetWaitReceiveAvail;
1996 pState->INetworkPort.pfnReceive = vnetReceive;
1997 pState->INetworkConfig.pfnGetMac = vnetGetMac;
1998 pState->INetworkConfig.pfnGetLinkState = vnetGetLinkState;
1999 pState->INetworkConfig.pfnSetLinkState = vnetSetLinkState;
2000
2001 /* Register save/restore state handlers. */
2002 rc = PDMDevHlpSSMRegisterEx(pDevIns, VNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
2003 NULL, vnetLiveExec, NULL,
2004 vnetSavePrep, vnetSaveExec, NULL,
2005 vnetLoadPrep, vnetLoadExec, NULL);
2006 if (RT_FAILURE(rc))
2007 return rc;
2008
2009 /* Create the RX notifier signaller. */
2010 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
2011 vnetCanRxQueueConsumer, true, "VNet-Rcv", &pState->pCanRxQueueR3);
2012 if (RT_FAILURE(rc))
2013 return rc;
2014 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
2015 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
2016
2017 /* Create Link Up Timer */
2018 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetLinkUpTimer, pState,
2019 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
2020 "VirtioNet Link Up Timer", &pState->pLinkUpTimer);
2021 if (RT_FAILURE(rc))
2022 return rc;
2023
2024 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
2025 if (RT_SUCCESS(rc))
2026 {
2027 if (rc == VINF_NAT_DNS)
2028 {
2029 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2030 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"));
2031 }
2032 pState->pDrv = (PPDMINETWORKCONNECTOR)
2033 pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
2034 if (!pState->pDrv)
2035 {
2036 AssertMsgFailed(("%s Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
2037 return VERR_PDM_MISSING_INTERFACE_BELOW;
2038 }
2039 }
2040 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2041 {
2042 Log(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
2043 }
2044 else
2045 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
2046
2047 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
2048 if (RT_FAILURE(rc))
2049 return rc;
2050
2051 vnetReset(pState);
2052
2053 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
2054 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
2055#if defined(VBOX_WITH_STATISTICS)
2056 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
2057 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
2058 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
2059 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
2060 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
2061#endif /* VBOX_WITH_STATISTICS */
2062
2063 return VINF_SUCCESS;
2064}
2065
2066/**
2067 * Destruct a device instance.
2068 *
2069 * We need to free non-VM resources only.
2070 *
2071 * @returns VBox status.
2072 * @param pDevIns The device instance data.
2073 * @thread EMT
2074 */
2075static DECLCALLBACK(int) vnetDestruct(PPDMDEVINS pDevIns)
2076{
2077 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2078
2079 Log(("%s Destroying instance\n", INSTANCE(pState)));
2080 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
2081 {
2082 RTSemEventSignal(pState->hEventMoreRxDescAvail);
2083 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
2084 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
2085 }
2086
2087 return vpciDestruct(&pState->VPCI);
2088}
2089
2090/**
2091 * Device relocation callback.
2092 *
2093 * When this callback is called the device instance data, and if the
2094 * device have a GC component, is being relocated, or/and the selectors
2095 * have been changed. The device must use the chance to perform the
2096 * necessary pointer relocations and data updates.
2097 *
2098 * Before the GC code is executed the first time, this function will be
2099 * called with a 0 delta so GC pointer calculations can be one in one place.
2100 *
2101 * @param pDevIns Pointer to the device instance.
2102 * @param offDelta The relocation delta relative to the old location.
2103 *
2104 * @remark A relocation CANNOT fail.
2105 */
2106static DECLCALLBACK(void) vnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2107{
2108 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2109 vpciRelocate(pDevIns, offDelta);
2110 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
2111 // TBD
2112}
2113
2114/**
2115 * @copydoc FNPDMDEVSUSPEND
2116 */
2117static DECLCALLBACK(void) vnetSuspend(PPDMDEVINS pDevIns)
2118{
2119 /* Poke thread waiting for buffer space. */
2120 vnetWakeupReceive(pDevIns);
2121}
2122
2123
2124#ifdef VBOX_DYNAMIC_NET_ATTACH
2125/**
2126 * Detach notification.
2127 *
2128 * One port on the network card has been disconnected from the network.
2129 *
2130 * @param pDevIns The device instance.
2131 * @param iLUN The logical unit which is being detached.
2132 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2133 */
2134static DECLCALLBACK(void) vnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2135{
2136 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2137 Log(("%s vnetDetach:\n", INSTANCE(pState)));
2138
2139 AssertLogRelReturnVoid(iLUN == 0);
2140
2141 vnetCsEnter(pState, VERR_SEM_BUSY);
2142
2143 /*
2144 * Zero some important members.
2145 */
2146 pState->pDrvBase = NULL;
2147 pState->pDrv = NULL;
2148
2149 vnetCsLeave(pState);
2150}
2151
2152
2153/**
2154 * Attach the Network attachment.
2155 *
2156 * One port on the network card has been connected to a network.
2157 *
2158 * @returns VBox status code.
2159 * @param pDevIns The device instance.
2160 * @param iLUN The logical unit which is being attached.
2161 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
2162 *
2163 * @remarks This code path is not used during construction.
2164 */
2165static DECLCALLBACK(int) vnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
2166{
2167 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
2168 LogFlow(("%s vnetAttach:\n", INSTANCE(pState)));
2169
2170 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
2171
2172 vnetCsEnter(pState, VERR_SEM_BUSY);
2173
2174 /*
2175 * Attach the driver.
2176 */
2177 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
2178 if (RT_SUCCESS(rc))
2179 {
2180 if (rc == VINF_NAT_DNS)
2181 {
2182#ifdef RT_OS_LINUX
2183 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2184 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"));
2185#else
2186 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
2187 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"));
2188#endif
2189 }
2190 pState->pDrv = (PPDMINETWORKCONNECTOR)pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
2191 if (!pState->pDrv)
2192 {
2193 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
2194 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
2195 }
2196 }
2197 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2198 Log(("%s No attached driver!\n", INSTANCE(pState)));
2199
2200
2201 /*
2202 * Temporary set the link down if it was up so that the guest
2203 * will know that we have change the configuration of the
2204 * network card
2205 */
2206 if (RT_SUCCESS(rc))
2207 vnetTempLinkDown(pState);
2208
2209 vnetCsLeave(pState);
2210 return rc;
2211
2212}
2213#endif /* VBOX_DYNAMIC_NET_ATTACH */
2214
2215
2216/**
2217 * @copydoc FNPDMDEVPOWEROFF
2218 */
2219static DECLCALLBACK(void) vnetPowerOff(PPDMDEVINS pDevIns)
2220{
2221 /* Poke thread waiting for buffer space. */
2222 vnetWakeupReceive(pDevIns);
2223}
2224
2225/**
2226 * The device registration structure.
2227 */
2228const PDMDEVREG g_DeviceVirtioNet =
2229{
2230 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
2231 PDM_DEVREG_VERSION,
2232 /* Device name. */
2233 "virtio-net",
2234 /* Name of guest context module (no path).
2235 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
2236 "VBoxDDGC.gc",
2237 /* Name of ring-0 module (no path).
2238 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
2239 "VBoxDDR0.r0",
2240 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
2241 * remain unchanged from registration till VM destruction. */
2242 "Virtio Ethernet.\n",
2243
2244 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
2245#ifdef VNET_GC_SUPPORT
2246 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2247#else
2248 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2249#endif
2250 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
2251 PDM_DEVREG_CLASS_NETWORK,
2252 /* Maximum number of instances (per VM). */
2253 8,
2254 /* Size of the instance data. */
2255 sizeof(VNETSTATE),
2256
2257 /* Construct instance - required. */
2258 vnetConstruct,
2259 /* Destruct instance - optional. */
2260 vnetDestruct,
2261 /* Relocation command - optional. */
2262 vnetRelocate,
2263 /* I/O Control interface - optional. */
2264 NULL,
2265 /* Power on notification - optional. */
2266 NULL,
2267 /* Reset notification - optional. */
2268 NULL,
2269 /* Suspend notification - optional. */
2270 vnetSuspend,
2271 /* Resume notification - optional. */
2272 NULL,
2273#ifdef VBOX_DYNAMIC_NET_ATTACH
2274 /* Attach command - optional. */
2275 vnetAttach,
2276 /* Detach notification - optional. */
2277 vnetDetach,
2278#else /* !VBOX_DYNAMIC_NET_ATTACH */
2279 /* Attach command - optional. */
2280 NULL,
2281 /* Detach notification - optional. */
2282 NULL,
2283#endif /* !VBOX_DYNAMIC_NET_ATTACH */
2284 /* Query a LUN base interface - optional. */
2285 NULL,
2286 /* Init complete notification - optional. */
2287 NULL,
2288 /* Power off notification - optional. */
2289 vnetPowerOff,
2290 /* pfnSoftReset */
2291 NULL,
2292 /* u32VersionEnd */
2293 PDM_DEVREG_VERSION
2294};
2295
2296#endif /* IN_RING3 */
2297#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2298
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