DevPCNet.cpp revision f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * DevPCNet - AMD PCnet-PCI II / PCnet-FAST III (Am79C970A / Am79C973) Ethernet Controller Emulation.
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * This software was written to be compatible with the specifications:
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * Copyright (C) 2006-2008 Sun Microsystems, Inc.
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * This file is part of VirtualBox Open Source Edition (OSE), as
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * available from http://www.virtualbox.org. This file is free software;
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * you can redistribute it and/or modify it under the terms of the GNU
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * General Public License (GPL) as published by the Free Software
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * Foundation, in version 2 as it comes in the "COPYING" file of the
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * Clara, CA 95054 USA or visit http://www.sun.com if you need
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * additional information or have any questions.
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * --------------------------------------------------------------------
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * This code is based on:
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * AMD PC-Net II (Am79C970A) emulation
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * Copyright (c) 2004 Antony T Curtis
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * Permission is hereby granted, free of charge, to any person obtaining a copy
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * of this software and associated documentation files (the "Software"), to deal
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * in the Software without restriction, including without limitation the rights
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * copies of the Software, and to permit persons to whom the Software is
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * furnished to do so, subject to the following conditions:
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * The above copyright notice and this permission notice shall be included in
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * all copies or substantial portions of the Software.
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore * THE SOFTWARE.
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/*******************************************************************************
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore* Header Files *
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore*******************************************************************************/
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/* Enable this to catch writes to the ring descriptors instead of using excessive polling */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/* #define PCNET_NO_POLLING */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/* Enable to handle frequent io reads in the guest context (recommended) */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/* Experimental: queue TX packets */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore//#define PCNET_QUEUE_SEND_PACKETS
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/* Maximum number of times we report a link down to the guest (failure to send frame) */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore/* Maximum frame size we handle */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Poll timer - R3. */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Poll timer - R0. */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Poll timer - RC. */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Software Interrupt timer - R3. */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Software Interrupt timer - R0. */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Software Interrupt timer - RC. */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Register Address Pointer */
4297a3b0d0a35d80f86fff155e288e885a100e6dGarrett D'Amore /** Internal interrupt service */
int iLog2DescSize;
bool fLinkUp;
bool fLinkTempDown;
bool volatile fMaybeOutOfSpace;
bool fSignalRxMiss;
#ifdef PCNET_NO_POLLING
DECLRCCALLBACKMEMBER(int, pfnEMInterpretInstructionRC, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
DECLR0CALLBACKMEMBER(int, pfnEMInterpretInstructionR0, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
bool fPrivIfEnabled;
bool fGCEnabled;
bool fR0Enabled;
bool fAm79C973;
#ifdef PCNET_QUEUE_SEND_PACKETS
#ifdef VBOX_WITH_STATISTICS
# ifdef PCNET_NO_POLLING
#define BCR_MSRDA 0
#define CSR_TDMD(S) !!((S)->aCSR[0] & 0x0008) /**< Transmit demand. (perform xmit poll now (readable, settable, not clearable) */
struct INITBLK16
struct INITBLK32
typedef struct TMD
} tmd0;
} tmd1;
} tmd2;
} tmd3;
} TMD;
typedef struct RMD
} rmd0;
} rmd1;
} rmd2;
} rmd3;
} RMD;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
/* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
#ifdef DEBUG
/* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
#ifdef DEBUG
#pragma pack()
#ifdef IN_RING3
return crc;
int result;
#ifdef PCNET_DEBUG_MATCH
return result;
#ifdef PCNET_DEBUG_MATCH
return result;
int index;
#ifndef IN_RING3
#ifdef PCNET_NO_POLLING
# ifndef IN_RING3
#ifdef PCNET_MONITOR_RECEIVE_RING
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
#ifdef PCNET_MONITOR_RECEIVE_RING
return VINF_SUCCESS;
register int iISR = 0;
#ifdef VBOX
LogRel(("PCNet#%d: %s private interface\n", PCNET_INST_NR, fPrivIfEnabled ? "Enabling" : "Disabling"));
#ifdef IN_RING3
#ifdef PCNET_NO_POLLING
int rc;
Log(("pcnetUpdateRingHandlers TD %RX32 size %#x -> %RX32 ?size? %#x\n", pThis->TDRAPhysOld, pThis->cbTDRAOld, pThis->GCTDRA, pcnetTdraAddr(pThis, 0)));
Log(("pcnetUpdateRingHandlers RX %RX32 size %#x -> %RX32 ?size? %#x\n", pThis->RDRAPhysOld, pThis->cbRDRAOld, pThis->GCRDRA, pcnetRdraAddr(pThis, 0)));
#ifdef PCNET_MONITOR_RECEIVE_RING
#ifdef PCNET_MONITOR_RECEIVE_RING
#ifdef PCNET_MONITOR_RECEIVE_RING
AssertFailed();
#define PCNET_INIT() do { \
PCNET_INIT();
PCNET_INIT();
#ifdef PCNET_NO_POLLING
#ifdef IN_RING3
if (!fSkipCurrent)
#ifdef IN_RING3
if (pItem)
#ifdef IN_RING3
int pkt_size;
int pktcount = 0;
#ifdef PCNET_DEBUG_MATCH
pktcount++;
while (size > 0)
pktcount++;
#ifdef PCNET_DEBUG_RMD
while (pktcount--)
#ifdef PCNET_QUEUE_SEND_PACKETS
DECLINLINE(void) pcnetXmitRead1st(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
#ifdef PCNET_QUEUE_SEND_PACKETS
DECLINLINE(void) pcnetXmitReadMore(PCNetState *pThis, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), GCPhysFrame, pThis->pvSendFrame + pThis->cbSendFrame, cbFrame);
#ifdef PCNET_QUEUE_SEND_PACKETS
return VINF_SUCCESS;
#ifdef IN_RING3
#ifdef IN_RING3
#ifdef PCNET_QUEUE_SEND_PACKETS
return VINF_SUCCESS;
unsigned cFlushIrq = 0;
return VINF_SUCCESS;
#ifdef VBOX_WITH_STATISTICS
#ifdef PCNET_DEBUG_TMD
bool fDropFrame = false;
#ifdef LOG_ENABLED
#ifdef VBOX_WITH_STATISTICS
cBuffers++;
&& !fDropFrame)
fDropFrame = true;
if (!fDropFrame)
/** @todo according to the specs we're supposed to clear the own bit and move on to the next one. */
cFlushIrq++;
/** @todo should we continue after an error (tmd.tmd1.err) or not? */
if (cFlushIrq)
STAM_COUNTER_INC(&pThis->aStatXmitFlush[RT_MIN(cFlushIrq, RT_ELEMENTS(pThis->aStatXmitFlush)) - 1]);
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
#ifdef LOG_ENABLED
#ifdef PCNET_DEBUG_TMD
#ifdef PCNET_NO_POLLING
#ifdef PCNET_DEBUG_CSR
switch (u32RAP)
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
#ifdef IN_RING3
return rc;
return rc;
#ifndef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
return rc;
Log(("#%d: WRITE CSR%d, %#06x => GCRDRA=%08x (alt init)\n", PCNET_INST_NR, u32RAP, val, pThis->GCRDRA));
return rc;
Log(("#%d: WRITE CSR%d, %#06x => GCTDRA=%08x (alt init)\n", PCNET_INST_NR, u32RAP, val, pThis->GCTDRA));
return rc;
return rc;
return rc;
unsigned exp = 0;
++exp;
switch (u32RAP)
#ifdef PCNET_DEBUG_CSR
return val;
#ifdef PCNET_DEBUG_BCR
switch (u32RAP)
case BCR_SWS:
return rc;
case BCR_LNKST:
case BCR_LED1:
case BCR_LED2:
case BCR_LED3:
case BCR_MC:
case BCR_FDC:
case BCR_BSBC:
case BCR_EECAS:
case BCR_PLAT:
case BCR_MIICAS:
case BCR_MIIADDR:
case BCR_STVAL:
case BCR_MIIMDR:
#ifdef PCNET_DEBUG_MII
return rc;
switch (miiaddr)
val = 0;
if (autoneg)
if (fast)
if (!autoneg) {
if (duplex)
if (fast)
val = 0;
val = 0;
val = 0;
#ifdef PCNET_DEBUG_MII
return val;
switch (u32RAP)
case BCR_LNKST:
case BCR_LED1:
case BCR_LED2:
case BCR_LED3:
case BCR_MIIMDR:
#ifdef PCNET_DEBUG_BCR
return val;
return val;
#ifdef PCNET_DEBUG_IO
return rc;
goto skip_update_irq;
goto skip_update_irq;
val = 0;
Log(("#%d pcnetIoportReadU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xffff));
#ifdef PCNET_DEBUG_IO
return val;
#ifdef PCNET_DEBUG_IO
#ifdef PCNET_DEBUG_IO
return rc;
goto skip_update_irq;
goto skip_update_irq;
val = 0;
#ifdef PCNET_DEBUG_IO
return val;
#ifdef PCNET_DEBUG_IO
#ifdef PCNET_DEBUG_IO
return val;
#ifdef PCNET_DEBUG_IO
int rc;
#ifdef PCNET_DEBUG_IO
return val;
#ifdef PCNET_DEBUG_IO
int rc;
#ifdef PCNET_DEBUG_IO
return val;
int rc;
LogFlow(("#%d pcnetIOPortAPromRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, *pu32, cb, rc));
return rc;
int rc;
LogFlow(("#%d pcnetIOPortAPromWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, u32, cb, rc));
#ifdef LOG_ENABLED
return rc;
switch (cb)
Log2(("#%d pcnetIOPortRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, *pu32, cb, rc));
#ifdef LOG_ENABLED
return rc;
switch (cb)
Log2(("#%d pcnetIOPortWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", PCNET_INST_NR, Port, u32, cb, rc));
#ifdef LOG_ENABLED
return rc;
switch (cb)
#ifdef LOG_ENABLED
return rc;
switch (cb)
#ifdef LOG_ENABLED
return rc;
#ifdef IN_RING3
int rc;
pThis->aCSR[0] &= ~(RT_BIT(15) | RT_BIT(13)); /* ERR | CERR - probably not 100% correct either... */
int rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return VINF_SUCCESS;
int rc;
return rc;
return rc;
return VINF_SUCCESS;
bool fRcvRing = false;
bool fXmtRing = false;
if (pszArgs)
pThis->fAm79C973 ? "Am79C973" : "Am79C970A", pThis->fGCEnabled ? " GC" : "", pThis->fR0Enabled ? " R0" : "");
PDMCritSectEnter(&pThis->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
"CSR3=%#06x: BSWP=%d EMBA=%d DXMT2PD=%d LAPPEN=%d DXSUFLO=%d IDONM=%d TINTM=%d RINTM=%d MERRM=%d MISSM=%d BABLM=%d\n",
!!(pThis->aCSR[3] & RT_BIT(2)), !!(pThis->aCSR[3] & RT_BIT(3)), !!(pThis->aCSR[3] & RT_BIT(4)), CSR_LAPPEN(pThis),
CSR_DXSUFLO(pThis), !!(pThis->aCSR[3] & RT_BIT(8)), !!(pThis->aCSR[3] & RT_BIT(9)), !!(pThis->aCSR[3] & RT_BIT(10)),
!!(pThis->aCSR[4] & RT_BIT( 0)), !!(pThis->aCSR[4] & RT_BIT( 1)), !!(pThis->aCSR[4] & RT_BIT( 2)), !!(pThis->aCSR[4] & RT_BIT( 3)),
!!(pThis->aCSR[4] & RT_BIT( 4)), !!(pThis->aCSR[4] & RT_BIT( 5)), !!(pThis->aCSR[4] & RT_BIT( 6)), !!(pThis->aCSR[4] & RT_BIT( 7)),
!!(pThis->aCSR[4] & RT_BIT( 8)), !!(pThis->aCSR[4] & RT_BIT( 9)), !!(pThis->aCSR[4] & RT_BIT(10)), !!(pThis->aCSR[4] & RT_BIT(11)),
!!(pThis->aCSR[4] & RT_BIT(12)), !!(pThis->aCSR[4] & RT_BIT(13)), !!(pThis->aCSR[4] & RT_BIT(14)), !!(pThis->aCSR[4] & RT_BIT(15)));
!!(pThis->aCSR[15] & RT_BIT( 0)), !!(pThis->aCSR[15] & RT_BIT( 1)), !!(pThis->aCSR[15] & RT_BIT( 2)), !!(pThis->aCSR[15] & RT_BIT( 3)),
!!(pThis->aCSR[15] & RT_BIT( 4)), !!(pThis->aCSR[15] & RT_BIT( 5)), !!(pThis->aCSR[15] & RT_BIT( 6)), (pThis->aCSR[15] >> 7) & 3,
!!(pThis->aCSR[15] & RT_BIT( 9)), !!(pThis->aCSR[15] & RT_BIT(10)), !!(pThis->aCSR[15] & RT_BIT(11)),
!!(pThis->aCSR[15] & RT_BIT(12)), !!(pThis->aCSR[15] & RT_BIT(13)), !!(pThis->aCSR[15] & RT_BIT(14)), !!(pThis->aCSR[15] & RT_BIT(15)));
!!(pThis->aCSR[58] & RT_BIT(8)), !!(pThis->aCSR[58] & RT_BIT(9)), !!(pThis->aCSR[58] & RT_BIT(10)));
if (fRcvRing)
if (fXmtRing)
return VINF_SUCCESS;
#ifdef PCNET_NO_POLLING
return VINF_SUCCESS;
return rc;
return rc;
return VINF_SUCCESS;
static DECLCALLBACK(int) pcnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
#ifndef PCNET_NO_POLLING
#ifdef PCNET_NO_POLLING
return VINF_SUCCESS;
static DECLCALLBACK(void *) pcnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
switch (enmInterface)
case PDMINTERFACE_BASE:
case PDMINTERFACE_LED_PORTS:
return NULL;
#define INETWORKPORT_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkPort)) )
return rc;
return VINF_SUCCESS;
return VERR_NET_NO_BUFFER_SPACE;
return rc;
int rc;
#ifdef LOG_ENABLED
static bool s_fFirstBigFrameLoss = true;
if (s_fFirstBigFrameLoss)
s_fFirstBigFrameLoss = false;
return VINF_SUCCESS;
#define INETWORKCONFIG_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkConfig)) )
return VINF_SUCCESS;
return PDMNETWORKLINKSTATE_UP;
return PDMNETWORKLINKSTATE_DOWN;
return PDMNETWORKLINKSTATE_DOWN_RESUME;
return PDMNETWORKLINKSTATE_INVALID;
static DECLCALLBACK(int) pcnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
bool fLinkUp;
return VERR_INVALID_PARAMETER;
if (fLinkUp)
pThis->aCSR[0] &= ~(RT_BIT(15) | RT_BIT(13)); /* ERR | CERR - probably not 100% correct either... */
return VINF_SUCCESS;
static DECLCALLBACK(int) pcnetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
if (iLUN == 0)
return VINF_SUCCESS;
return VERR_PDM_LUN_NOT_FOUND;
#ifdef PCNET_NO_POLLING
#ifdef PCNET_QUEUE_SEND_PACKETS
return VINF_SUCCESS;
int rc;
if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0" "CableConnected\0" "Am79C973\0" "LineSpeed\0" "GCEnabled\0" "R0Enabled\0" "PrivIfEnabled\0"))
rc = CFGMR3QueryU32Def(pCfgHandle, "LineSpeed", &pThis->u32LinkSpeed, 1000000); /* 1GBit/s (in kbps units)*/
#ifdef PCNET_GC_ENABLED
return rc;
return rc;
return rc;
bool fPrivIfEnabled;
fPrivIfEnabled = true;
if (fPrivIfEnabled)
* should not care if there is an additional PCI ressource but just in case we made this configurable.
rc = PDMDevHlpMMIO2Register(pDevIns, 2, PCNET_GUEST_SHARED_MEMORY_SIZE, 0, (void **)&pThis->pSharedMMIOR3, "PCNetShMem");
return rc;
#ifdef PCNET_NO_POLLING
rc = PDMR3LdrGetSymbolR0Lazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", &pThis->pfnEMInterpretInstructionR0);
rc = PDMR3LdrGetSymbolRCLazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pThis->pfnEMInterpretInstructionRC);
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
return rc;
#ifdef RT_OS_LINUX
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"));
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"));
return VERR_PDM_MISSING_INTERFACE_BELOW;
return rc;
rc = PDMDevHlpPDMThreadCreate(pDevIns, &pThis->pSendThread, pThis, pcnetAsyncSendThread, pcnetAsyncSendThreadWakeUp, 0, RTTHREADTYPE_IO, "PCNET_TX");
#ifdef PCNET_QUEUE_SEND_PACKETS
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/PCNet%d/MMIO/ReadGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/PCNet%d/MMIO/ReadHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/PCNet%d/MMIO/WriteGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/PCNet%d/MMIO/WriteHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatAPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM reads", "/Devices/PCNet%d/IO/APROMRead", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatAPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM writes", "/Devices/PCNet%d/IO/APROMWrite", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in GC", "/Devices/PCNet%d/IO/ReadGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in HC", "/Devices/PCNet%d/IO/ReadHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in GC", "/Devices/PCNet%d/IO/WriteGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC", "/Devices/PCNet%d/IO/WriteHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling Timer", "/Devices/PCNet%d/Timer", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/PCNet%d/Receive", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/PCNet%d/RxOverflow", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflowWakeup, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Nr of RX overflow wakeups", "/Devices/PCNet%d/RxOverflowWakeup", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/PCNet%d/ReceiveBytes", iInstance);
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/PCNet%d/Transmit/Total", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/PCNet%d/TransmitBytes", iInstance);
#ifdef VBOX_WITH_STATISTICS
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet send transmit in HC","/Devices/PCNet%d/Transmit/Send", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in GC", "/Devices/PCNet%d/TdtePollGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in HC", "/Devices/PCNet%d/TdtePollHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in GC", "/Devices/PCNet%d/RdtePollGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in HC", "/Devices/PCNet%d/RdtePollHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTmdStoreGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in GC", "/Devices/PCNet%d/TmdStoreGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTmdStoreHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in HC", "/Devices/PCNet%d/TmdStoreHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d", iInstance, i + 1);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d+", iInstance, i + 1);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d", iInstance, i + 1);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d+", iInstance, i + 1);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatXmitSkipCurrent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/Xmit/Skipped", iInstance, i + 1);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling interrupt checks", "/Devices/PCNet%d/UpdateIRQ", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatPollTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling poll timer", "/Devices/PCNet%d/PollTimer", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMIIReads, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of MII reads", "/Devices/PCNet%d/MIIReads", iInstance);
# ifdef PCNET_NO_POLLING
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRCVRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of receive ring writes", "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTXRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of transmit ring writes", "/Devices/PCNet%d/Ring/TXWrites", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteFailedHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteFailedR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteFailedGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteOutsideHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring","/Devices/PCNet%d/Ring/HC/Outside", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteOutsideR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring","/Devices/PCNet%d/Ring/R0/Outside", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRingWriteOutsideGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring","/Devices/PCNet%d/Ring/GC/Outside", iInstance);
return VINF_SUCCESS;
#ifdef PCNET_GC_ENABLED
#ifdef PCNET_GC_ENABLED
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
sizeof(PCNetState),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,