VirtualBox

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

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

#3987: Virtio: LEDs are done.

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