DevPCNet.cpp revision 571c90a734400801da973f986190fac9fc5efd0d
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * DevPCNet - AMD PCnet-PCI II / PCnet-FAST III (Am79C970A / Am79C973) Ethernet Controller Emulation.
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * This software was written to be compatible with the specifications:
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * Copyright (C) 2006-2008 Sun Microsystems, Inc.
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * This file is part of VirtualBox Open Source Edition (OSE), as
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * available from http://www.virtualbox.org. This file is free software;
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * you can redistribute it and/or modify it under the terms of the GNU
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * General Public License (GPL) as published by the Free Software
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * Foundation, in version 2 as it comes in the "COPYING" file of the
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * Clara, CA 95054 USA or visit http://www.sun.com if you need
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * additional information or have any questions.
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * --------------------------------------------------------------------
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * This code is based on:
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * AMD PC-Net II (Am79C970A) emulation
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * Copyright (c) 2004 Antony T Curtis
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * Permission is hereby granted, free of charge, to any person obtaining a copy
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * of this software and associated documentation files (the "Software"), to deal
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * in the Software without restriction, including without limitation the rights
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * copies of the Software, and to permit persons to whom the Software is
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * furnished to do so, subject to the following conditions:
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * The above copyright notice and this permission notice shall be included in
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * all copies or substantial portions of the Software.
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * THE SOFTWARE.
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/*******************************************************************************
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico* Header Files *
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico*******************************************************************************/
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico/* Enable this to catch writes to the ring descriptors instead of using excessive polling */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico/* #define PCNET_NO_POLLING */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/* Enable to handle frequent io reads in the guest context (recommended) */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico/* Experimental: queue TX packets */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico//#define PCNET_QUEUE_SEND_PACKETS
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/* Maximum number of times we report a link down to the guest (failure to send frame) */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico/* Maximum frame size we handle */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Poll timer - R3. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Poll timer - R0. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Poll timer - RC. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Software Interrupt timer - R3. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Software Interrupt timer - R0. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Software Interrupt timer - RC. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Register Address Pointer */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Internal interrupt service */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Address of the RX descriptor table (ring). Loaded at init. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Address of the TX descriptor table (ring). Loaded at init. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Last time we polled the queues */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Size of current send frame */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Buffer address of current send frame */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** The xmit buffer. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** The recv buffer. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Pending send packet counter. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Size of a RX/TX descriptor (8 or 16 bytes according to SWSTYLE */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Bits 16..23 in 16-bit mode */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Transmit signaller - RC. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Transmit signaller - R3. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Transmit signaller - R0. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Receive signaller - R3. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Receive signaller - R0. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Receive signaller - RC. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Pointer to the device instance - RC. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Pointer to the device instance - R3. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Pointer to the device instance - R0. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Restore timer.
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * This is used to disconnect and reconnect the link after a restore. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** Pointer to the connector of the attached network driver. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Pointer to the attached network driver. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The base interface. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** The network port interface. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The network config port interface. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Base address of the MMIO region. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Base port of the I/O space region. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** If set the link is currently up. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** If set the link is temporarily down because of a saved state load. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Number of times we've reported the link down. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** The configured MAC address. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Alignment padding. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** The LED. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** The LED ports. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Partner of ILeds. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Async send thread */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The Async send thread. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** Access critical section. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** Event semaphore for blocking on receive. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** We are waiting/about to start waiting for more receive buffers. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** True if we signal the guest that RX packets are missing. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico DECLRCCALLBACKMEMBER(int, pfnEMInterpretInstructionRC, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico DECLR0CALLBACKMEMBER(int, pfnEMInterpretInstructionR0, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico /** The shared memory used for the private interface - R3. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico /** The shared memory used for the private interface - R0. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** The shared memory used for the private interface - RC. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** True if host and guest admitted to use the private interface. */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico# define PCNET_MAX_XMIT_SLOTS_MASK (PCNET_MAX_XMIT_SLOTS - 1)
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /** @todo XXX currently atomic operations on this variable are overkill */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico R3PTRTYPE(uint8_t *) apXmitRingBuffer[PCNET_MAX_XMIT_SLOTS];
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#endif /* VBOX_WITH_STATISTICS */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define PCNETSTATE_2_DEVINS(pPCNet) ((pPCNet)->CTX_SUFF(pDevIns))
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define PCIDEV_2_PCNETSTATE(pPciDev) ((PCNetState *)(pPciDev))
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define PCNET_INST_NR (PCNETSTATE_2_DEVINS(pThis)->iInstance)
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/* BUS CONFIGURATION REGISTERS */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/* 10 - 15 = reserved */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define BCR_DWIO(S) !!((S)->aBCR[BCR_BSBC] & 0x0080)
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define BCR_SSIZE32(S) !!((S)->aBCR[BCR_SWS ] & 0x0100)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#define BCR_SWSTYLE(S) ((S)->aBCR[BCR_SWS ] & 0x00FF)
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_INIT(S) !!((S)->aCSR[0] & 0x0001) /**< Init assertion */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_STRT(S) !!((S)->aCSR[0] & 0x0002) /**< Start assertion */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_STOP(S) !!((S)->aCSR[0] & 0x0004) /**< Stop assertion */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_TDMD(S) !!((S)->aCSR[0] & 0x0008) /**< Transmit demand. (perform xmit poll now (readable, settable, not clearable) */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_TXON(S) !!((S)->aCSR[0] & 0x0010) /**< Transmit on (readonly) */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_RXON(S) !!((S)->aCSR[0] & 0x0020) /**< Receive On */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_INEA(S) !!((S)->aCSR[0] & 0x0040) /**< Interrupt Enable */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_LAPPEN(S) !!((S)->aCSR[3] & 0x0020) /**< Look Ahead Packet Processing Enable */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_DXSUFLO(S) !!((S)->aCSR[3] & 0x0040) /**< Disable Transmit Stop on Underflow error */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_ASTRP_RCV(S) !!((S)->aCSR[4] & 0x0400) /**< Auto Strip Receive */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_DPOLL(S) !!((S)->aCSR[4] & 0x1000) /**< Disable Transmit Polling */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_SPND(S) !!((S)->aCSR[5] & 0x0001) /**< Suspend */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_LTINTEN(S) !!((S)->aCSR[5] & 0x4000) /**< Last Transmit Interrupt Enable */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_TOKINTD(S) !!((S)->aCSR[5] & 0x8000) /**< Transmit OK Interrupt Disable */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_STINT !!((S)->aCSR[7] & 0x0800) /**< Software Timer Interrupt */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_STINTE !!((S)->aCSR[7] & 0x0400) /**< Software Timer Interrupt Enable */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_DRX(S) !!((S)->aCSR[15] & 0x0001) /**< Disable Receiver */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_DTX(S) !!((S)->aCSR[15] & 0x0002) /**< Disable Transmit */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_LOOP(S) !!((S)->aCSR[15] & 0x0004) /**< Loopback Enable */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_DRCVPA(S) !!((S)->aCSR[15] & 0x2000) /**< Disable Receive Physical Address */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#define CSR_DRCVBC(S) !!((S)->aCSR[15] & 0x4000) /**< Disable Receive Broadcast */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_PROM(S) !!((S)->aCSR[15] & 0x8000) /**< Promiscuous Mode */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#error fix macros (and more in this file) for big-endian machines
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_IADR(S) (*(uint32_t*)((S)->aCSR + 1)) /**< Initialization Block Address */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_CRBA(S) (*(uint32_t*)((S)->aCSR + 18)) /**< Current Receive Buffer Address */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_CXBA(S) (*(uint32_t*)((S)->aCSR + 20)) /**< Current Transmit Buffer Address */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_NRBA(S) (*(uint32_t*)((S)->aCSR + 22)) /**< Next Receive Buffer Address */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_BADR(S) (*(uint32_t*)((S)->aCSR + 24)) /**< Base Address of Receive Ring */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_NRDA(S) (*(uint32_t*)((S)->aCSR + 26)) /**< Next Receive Descriptor Address */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_CRDA(S) (*(uint32_t*)((S)->aCSR + 28)) /**< Current Receive Descriptor Address */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_BADX(S) (*(uint32_t*)((S)->aCSR + 30)) /**< Base Address of Transmit Descriptor */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_NXDA(S) (*(uint32_t*)((S)->aCSR + 32)) /**< Next Transmit Descriptor Address */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_CXDA(S) (*(uint32_t*)((S)->aCSR + 34)) /**< Current Transmit Descriptor Address */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_NNRD(S) (*(uint32_t*)((S)->aCSR + 36)) /**< Next Next Receive Descriptor Address */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_NNXD(S) (*(uint32_t*)((S)->aCSR + 38)) /**< Next Next Transmit Descriptor Address */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_CRBC(S) ((S)->aCSR[40]) /**< Current Receive Byte Count */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_CRST(S) ((S)->aCSR[41]) /**< Current Receive Status */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_CXBC(S) ((S)->aCSR[42]) /**< Current Transmit Byte Count */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_CXST(S) ((S)->aCSR[43]) /**< Current transmit status */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#define CSR_NRBC(S) ((S)->aCSR[44]) /**< Next Receive Byte Count */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_NRST(S) ((S)->aCSR[45]) /**< Next Receive Status */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_POLL(S) ((S)->aCSR[46]) /**< Transmit Poll Time Counter */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_PINT(S) ((S)->aCSR[47]) /**< Transmit Polling Interval */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico#define CSR_PXDA(S) (*(uint32_t*)((S)->aCSR + 60)) /**< Previous Transmit Descriptor Address*/
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_PXBC(S) ((S)->aCSR[62]) /**< Previous Transmit Byte Count */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_PXST(S) ((S)->aCSR[63]) /**< Previous Transmit Status */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_NXBA(S) (*(uint32_t*)((S)->aCSR + 64)) /**< Next Transmit Buffer Address */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_NXBC(S) ((S)->aCSR[66]) /**< Next Transmit Byte Count */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_NXST(S) ((S)->aCSR[67]) /**< Next Transmit Status */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_RCVRC(S) ((S)->aCSR[72]) /**< Receive Descriptor Ring Counter */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_XMTRC(S) ((S)->aCSR[74]) /**< Transmit Descriptor Ring Counter */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_RCVRL(S) ((S)->aCSR[76]) /**< Receive Descriptor Ring Length */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_XMTRL(S) ((S)->aCSR[78]) /**< Transmit Descriptor Ring Length */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_MISSC(S) ((S)->aCSR[112]) /**< Missed Frame Count */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/* Version for the PCnet/FAST III 79C973 card */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico#define CSR_VERSION_LOW_79C973 0x5003 /* the lower two bits must be 11b for AMD */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#define CSR_VERSION_LOW_79C970A 0x1003 /* the lower two bits must be 11b for AMD */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/** @todo All structs: big endian? */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint16_t ladrf1; /**< logical address filter 0..15 */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint16_t ladrf2; /**< logical address filter 16..31 */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint16_t ladrf3; /**< logical address filter 32..47 */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint16_t ladrf4; /**< logical address filter 48..63 */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint32_t rdra:24; /**< address of receive descriptor ring */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t rlen:3; /**< number of receive descriptor ring entries */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t tdra:24; /**< address of transmit descriptor ring */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t tlen:3; /**< number of transmit descriptor ring entries */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/** bird: I've changed the type for the bitfields. They should only be 16-bit all together.
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * frank: I've changed the bitfiled types to uint32_t to prevent compiler warnings. */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint16_t rlen:4; /**< number of receive descriptor ring entries */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint16_t tlen:4; /**< number of transmit descriptor ring entries */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint16_t ladrf1; /**< logical address filter 0..15 */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint16_t ladrf2; /**< logical address filter 16..31 */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint16_t ladrf3; /**< logibal address filter 32..47 */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint16_t ladrf4; /**< logical address filter 48..63 */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t rdra; /**< address of receive descriptor ring */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t tdra; /**< address of transmit descriptor ring */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/** Transmit Message Descriptor */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNicotypedef struct TMD
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t bcnt:12; /**< buffer byte count (two's complement) */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t one:1; /**< exactly one retry was needed to transmit a frame */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t ltint:1; /**< suppress interrupts after successful transmission */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t nofcs:1; /**< when set, the state of DXMTFCS is ignored and
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico transmitter FCS generation is activated. */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico uint32_t buff:1; /**< out of buffers (ENP not found) */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t res; /**< reserved for user defined space */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico/** Receive Message Descriptor */
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNicotypedef struct RMD
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t bcnt:12; /**< buffer byte count (two's complement) */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t lafm:1; /**< logical filter address match */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t crc:1; /**< crc error on incoming frame */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t oflo:1; /**< overflow error (lost all or part of incoming frame) */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t rcc:8; /**< receive frame tag + reserved */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico uint32_t res; /**< reserved for user defined space */
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico/*******************************************************************************
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico* Internal Functions *
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico*******************************************************************************/
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico "TMD0 : TBADR=%#010x\n" \
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico " BPE=%d, BCNT=%d\n" \
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico "LCA=%d, RTR=%d,\n" \
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico " TDR=%d, TRC=%d\n", \
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico "RMD0 : RBADR=%#010x\n" \
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico#if defined(PCNET_QUEUE_SEND_PACKETS) && defined(IN_RING3)
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNicostatic void pcnetPollTimerStart(PCNetState *pThis);
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * Load transmit message descriptor
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * Make sure we read the own flag first.
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico * @param pThis adapter private data
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico * @param addr physical address of the descriptor
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico * @return true if we own the descriptor, false otherwise
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNicoDECLINLINE(bool) pcnetTmdLoad(PCNetState *pThis, TMD *tmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico /* RX/TX descriptors shared between host and guest => direct copy */
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico uint8_t *pv = (uint8_t*)pThis->CTX_SUFF(pSharedMMIO)
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico + pThis->CTX_SUFF(pSharedMMIO)->V.V1.offTxDescriptors;
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico return false;
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico return true;
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico return false;
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
7b4a4ad907cbdb4ef453b43aa5739366bbaed5ceJazzyNico ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico return false;
b03d807cabe441e5a12c048e43c083a0954f7e58JazzyNico return false;
cb3fc841a44ecd9584fb55c9241e1ff8ee860926JazzyNico PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
/* 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
#ifdef IN_RING3
#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
unsigned iRxDesc;
int cbPacket;
while (iRxDesc-- > 0)
#ifdef PCNET_DEBUG_MATCH
while (cbToRecv > 0)
#ifdef PCNET_DEBUG_RMD
#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;
val = 0;
Log(("#%d pcnetIoportReadU8: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xff));
#ifdef PCNET_DEBUG_IO
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
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 VBOX_DYNAMIC_NET_ATTACH
#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"));
pThis->pDrv = (PPDMINETWORKCONNECTOR)pThis->pDrvBase->pfnQueryInterface(pThis->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
return rc;
#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;
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;
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerSoftInt, pThis, /** @todo r=bird: the locking here looks bogus now with SMP... */
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
sizeof(PCNetState),
NULL,
NULL,
NULL,
#ifdef VBOX_DYNAMIC_NET_ATTACH
NULL,
NULL,
NULL,
NULL,
NULL,