VirtualBox

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

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

#3987: Virtio: Applied Frank's GC patch and made debug build work as well.

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