VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevPCNet.cpp@ 7809

Last change on this file since 7809 was 7795, checked in by vboxsync, 17 years ago

PCNet: allow the guest to disable/enable the private interface

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 185.4 KB
Line 
1/* $Id: DevPCNet.cpp 7795 2008-04-08 12:02:15Z vboxsync $ */
2/** @file
3 * AMD PCnet-PCI II / PCnet-FAST III (Am79C970A / Am79C973) Ethernet Controller Emulation.
4 */
5
6/*
7 * Copyright (C) 2006-2008 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on:
19 *
20 * AMD PC-Net II (Am79C970A) emulation
21 *
22 * Copyright (c) 2004 Antony T Curtis
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 */
42
43/* This software was written to be compatible with the specification:
44 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
45 * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
46 */
47
48/*******************************************************************************
49* Header Files *
50*******************************************************************************/
51#define LOG_GROUP LOG_GROUP_DEV_PCNET
52#include <VBox/pdmdev.h>
53#include <VBox/pgm.h>
54#include <VBox/vm.h> /* for VM_IS_EMT */
55#include <VBox/DevPCNet.h>
56#include <iprt/asm.h>
57#include <iprt/assert.h>
58#include <iprt/critsect.h>
59#include <iprt/string.h>
60#include <iprt/time.h>
61#ifdef IN_RING3
62# include <iprt/mem.h>
63# include <iprt/semaphore.h>
64#endif
65
66#include "Builtins.h"
67
68/* Enable this to catch writes to the ring descriptors instead of using excessive polling */
69/* #define PCNET_NO_POLLING */
70
71/* Enable to handle frequent io reads in the guest context (recommended) */
72#define PCNET_GC_ENABLED
73
74/* Experimental: queue TX packets */
75//#define PCNET_QUEUE_SEND_PACKETS
76
77#if defined(LOG_ENABLED)
78#define PCNET_DEBUG_IO
79#define PCNET_DEBUG_BCR
80#define PCNET_DEBUG_CSR
81#define PCNET_DEBUG_RMD
82#define PCNET_DEBUG_TMD
83#define PCNET_DEBUG_MATCH
84#define PCNET_DEBUG_MII
85#endif
86
87#define PCNET_IOPORT_SIZE 0x20
88#define PCNET_PNPMMIO_SIZE 0x20
89
90#define PCNET_SAVEDSTATE_VERSION 9
91
92#define BCR_MAX_RAP 50
93#define MII_MAX_REG 32
94#define CSR_MAX_REG 128
95
96/* Maximum number of times we report a link down to the guest (failure to send frame) */
97#define PCNET_MAX_LINKDOWN_REPORTED 3
98
99/* Maximum frame size we handle */
100#define MAX_FRAME 1536
101
102
103typedef struct PCNetState_st PCNetState;
104
105struct PCNetState_st
106{
107 PCIDEVICE PciDev;
108#ifndef PCNET_NO_POLLING
109 /** Poll timer (address for host context) */
110 R3R0PTRTYPE(PTMTIMER) pTimerPollHC;
111 /** Poll timer (address for guest context) */
112 GCPTRTYPE(PTMTIMER) pTimerPollGC;
113#endif
114
115#if HC_ARCH_BITS == 64
116 uint32_t Alignment;
117#endif
118
119 /** Software Interrupt timer (address for host context) */
120 R3R0PTRTYPE(PTMTIMER) pTimerSoftIntHC;
121 /** Software Interrupt timer (address for guest context) */
122 GCPTRTYPE(PTMTIMER) pTimerSoftIntGC;
123
124 /** Register Address Pointer */
125 uint32_t u32RAP;
126 /** Internal interrupt service */
127 int32_t iISR;
128 /** ??? */
129 uint32_t u32Lnkst;
130 /** Address of the RX descriptor table (ring). Loaded at init. */
131 RTGCPHYS32 GCRDRA;
132 /** Address of the TX descriptor table (ring). Loaded at init. */
133 RTGCPHYS32 GCTDRA;
134 uint8_t aPROM[16];
135 uint16_t aCSR[CSR_MAX_REG];
136 uint16_t aBCR[BCR_MAX_RAP];
137 uint16_t aMII[MII_MAX_REG];
138 uint16_t u16CSR0LastSeenByGuest;
139 uint16_t Alignment0[HC_ARCH_BITS == 32 ? 2 : 4];
140 /** Last time we polled the queues */
141 uint64_t u64LastPoll;
142
143 /** Size of current send frame */
144 uint32_t cbSendFrame;
145#if HC_ARCH_BITS == 64
146 uint32_t Alignment2;
147#endif
148 /** Buffer address of current send frame */
149 R3PTRTYPE(uint8_t *) pvSendFrame;
150 /** The xmit buffer. */
151 uint8_t abSendBuf[4096];
152 /** The recv buffer. */
153 uint8_t abRecvBuf[4096];
154
155 /** Pending send packet counter. */
156 uint32_t cPendingSends;
157
158 /** Size of a RX/TX descriptor (8 or 16 bytes according to SWSTYLE */
159 int iLog2DescSize;
160 /** Bits 16..23 in 16-bit mode */
161 RTGCPHYS32 GCUpperPhys;
162
163 /** Transmit signaller */
164 GCPTRTYPE(PPDMQUEUE) pXmitQueueGC;
165 R3R0PTRTYPE(PPDMQUEUE) pXmitQueueHC;
166
167 /** Receive signaller */
168 R3R0PTRTYPE(PPDMQUEUE) pCanRxQueueHC;
169 GCPTRTYPE(PPDMQUEUE) pCanRxQueueGC;
170 /** Pointer to the device instance. */
171 GCPTRTYPE(PPDMDEVINS) pDevInsGC;
172 /** Pointer to the device instance. */
173 R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
174 /** Restore timer.
175 * This is used to disconnect and reconnect the link after a restore. */
176 PTMTIMERR3 pTimerRestore;
177 /** Pointer to the connector of the attached network driver. */
178 R3PTRTYPE(PPDMINETWORKCONNECTOR) pDrv;
179 /** Pointer to the attached network driver. */
180 R3PTRTYPE(PPDMIBASE) pDrvBase;
181 /** The base interface. */
182 PDMIBASE IBase;
183 /** The network port interface. */
184 PDMINETWORKPORT INetworkPort;
185 /** The network config port interface. */
186 PDMINETWORKCONFIG INetworkConfig;
187 /** Base address of the MMIO region. */
188 RTGCPHYS32 MMIOBase;
189 /** Base port of the I/O space region. */
190 RTIOPORT IOPortBase;
191 /** If set the link is currently up. */
192 bool fLinkUp;
193 /** If set the link is temporarily down because of a saved state load. */
194 bool fLinkTempDown;
195
196 /** Number of times we've reported the link down. */
197 RTUINT cLinkDownReported;
198 /** The configured MAC address. */
199 PDMMAC MacConfigured;
200 /** Alignment padding. */
201 uint8_t Alignment4[HC_ARCH_BITS == 64 ? 6 : 2];
202
203 /** The LED. */
204 PDMLED Led;
205 /** The LED ports. */
206 PDMILEDPORTS ILeds;
207 /** Partner of ILeds. */
208 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
209
210 /** Async send thread */
211 RTSEMEVENT hSendEventSem;
212 /** The Async send thread. */
213 PPDMTHREAD pSendThread;
214
215 /** Access critical section. */
216 PDMCRITSECT CritSect;
217
218#ifdef PCNET_NO_POLLING
219 RTGCPHYS32 TDRAPhysOld;
220 uint32_t cbTDRAOld;
221
222 RTGCPHYS32 RDRAPhysOld;
223 uint32_t cbRDRAOld;
224
225 DECLGCCALLBACKMEMBER(int, pfnEMInterpretInstructionGC, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
226 DECLR0CALLBACKMEMBER(int, pfnEMInterpretInstructionR0, (PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, uint32_t *pcbSize));
227#endif
228
229 /** The host context of the shared memory used for the private interface. */
230 R3R0PTRTYPE(PPCNETGUESTSHAREDMEMORY) pSharedMMIOHC;
231 /** The hypervisor/guest context of the shared memory used for the private interface. */
232 GCPTRTYPE(PPCNETGUESTSHAREDMEMORY) pSharedMMIOGC;
233
234#if HC_ARCH_BITS == 64
235 uint32_t Alignment3;
236#endif
237
238 /** True if host and guest admitted to use the private interface. */
239 bool fPrivIfEnabled;
240 bool fGCEnabled;
241 bool fR0Enabled;
242 bool fAm79C973;
243 uint32_t u32LinkSpeed;
244
245#ifdef PCNET_QUEUE_SEND_PACKETS
246 #define PCNET_MAX_XMIT_SLOTS 128
247 #define PCNET_MAX_XMIT_SLOTS_MASK (PCNET_MAX_XMIT_SLOTS-1)
248
249 uint32_t iXmitRingBufProd;
250 uint32_t iXmitRingBufCons;
251 /* XXX currently atomic operations on this variable are overkill */
252 volatile int32_t cXmitRingBufPending;
253 uint16_t cbXmitRingBuffer[PCNET_MAX_XMIT_SLOTS];
254 R3PTRTYPE(uint8_t *) apXmitRingBuffer[PCNET_MAX_XMIT_SLOTS];
255#endif
256
257 STAMCOUNTER StatReceiveBytes;
258 STAMCOUNTER StatTransmitBytes;
259#ifdef VBOX_WITH_STATISTICS
260 STAMPROFILEADV StatMMIOReadGC;
261 STAMPROFILEADV StatMMIOReadHC;
262 STAMPROFILEADV StatMMIOWriteGC;
263 STAMPROFILEADV StatMMIOWriteHC;
264 STAMPROFILEADV StatAPROMRead;
265 STAMPROFILEADV StatAPROMWrite;
266 STAMPROFILEADV StatIOReadGC;
267 STAMPROFILEADV StatIOReadHC;
268 STAMPROFILEADV StatIOWriteGC;
269 STAMPROFILEADV StatIOWriteHC;
270 STAMPROFILEADV StatTimer;
271 STAMPROFILEADV StatReceive;
272 STAMPROFILEADV StatTransmit;
273 STAMPROFILEADV StatTransmitSend;
274 STAMPROFILEADV StatTdtePollGC;
275 STAMPROFILEADV StatTdtePollHC;
276 STAMPROFILEADV StatTmdStoreGC;
277 STAMPROFILEADV StatTmdStoreHC;
278 STAMPROFILEADV StatRdtePollGC;
279 STAMPROFILEADV StatRdtePollHC;
280 STAMCOUNTER aStatXmitFlush[16];
281 STAMCOUNTER aStatXmitChainCounts[16];
282 STAMCOUNTER StatXmitSkipCurrent;
283 STAMPROFILEADV StatInterrupt;
284 STAMPROFILEADV StatPollTimer;
285 STAMCOUNTER StatMIIReads;
286# ifdef PCNET_NO_POLLING
287 STAMCOUNTER StatRCVRingWrite;
288 STAMCOUNTER StatTXRingWrite;
289 STAMCOUNTER StatRingWriteHC;
290 STAMCOUNTER StatRingWriteR0;
291 STAMCOUNTER StatRingWriteGC;
292
293 STAMCOUNTER StatRingWriteFailedHC;
294 STAMCOUNTER StatRingWriteFailedR0;
295 STAMCOUNTER StatRingWriteFailedGC;
296
297 STAMCOUNTER StatRingWriteOutsideRangeHC;
298 STAMCOUNTER StatRingWriteOutsideRangeR0;
299 STAMCOUNTER StatRingWriteOutsideRangeGC;
300# endif
301#endif /* VBOX_WITH_STATISTICS */
302};
303
304#define PCNETSTATE_2_DEVINS(pPCNet) ((pPCNet)->CTXSUFF(pDevIns))
305#define PCIDEV_2_PCNETSTATE(pPciDev) ((PCNetState *)(pPciDev))
306#define PCNET_INST_NR (PCNETSTATE_2_DEVINS(pData)->iInstance)
307
308/* BUS CONFIGURATION REGISTERS */
309#define BCR_MSRDA 0
310#define BCR_MSWRA 1
311#define BCR_MC 2
312#define BCR_RESERVED3 3
313#define BCR_LNKST 4
314#define BCR_LED1 5
315#define BCR_LED2 6
316#define BCR_LED3 7
317#define BCR_RESERVED8 8
318#define BCR_FDC 9
319/* 10 - 15 = reserved */
320#define BCR_IOBASEL 16 /* Reserved */
321#define BCR_IOBASEU 16 /* Reserved */
322#define BCR_BSBC 18
323#define BCR_EECAS 19
324#define BCR_SWS 20
325#define BCR_INTCON 21 /* Reserved */
326#define BCR_PLAT 22
327#define BCR_PCISVID 23
328#define BCR_PCISID 24
329#define BCR_SRAMSIZ 25
330#define BCR_SRAMB 26
331#define BCR_SRAMIC 27
332#define BCR_EBADDRL 28
333#define BCR_EBADDRU 29
334#define BCR_EBD 30
335#define BCR_STVAL 31
336#define BCR_MIICAS 32
337#define BCR_MIIADDR 33
338#define BCR_MIIMDR 34
339#define BCR_PCIVID 35
340#define BCR_PMC_A 36
341#define BCR_DATA0 37
342#define BCR_DATA1 38
343#define BCR_DATA2 39
344#define BCR_DATA3 40
345#define BCR_DATA4 41
346#define BCR_DATA5 42
347#define BCR_DATA6 43
348#define BCR_DATA7 44
349#define BCR_PMR1 45
350#define BCR_PMR2 46
351#define BCR_PMR3 47
352
353#define BCR_DWIO(S) !!((S)->aBCR[BCR_BSBC] & 0x0080)
354#define BCR_SSIZE32(S) !!((S)->aBCR[BCR_SWS ] & 0x0100)
355#define BCR_SWSTYLE(S) ((S)->aBCR[BCR_SWS ] & 0x00FF)
356
357#define CSR_INIT(S) !!((S)->aCSR[0] & 0x0001) /**< Init assertion */
358#define CSR_STRT(S) !!((S)->aCSR[0] & 0x0002) /**< Start assertion */
359#define CSR_STOP(S) !!((S)->aCSR[0] & 0x0004) /**< Stop assertion */
360#define CSR_TDMD(S) !!((S)->aCSR[0] & 0x0008) /**< Transmit demand. (perform xmit poll now (readable, settable, not clearable) */
361#define CSR_TXON(S) !!((S)->aCSR[0] & 0x0010) /**< Transmit on (readonly) */
362#define CSR_RXON(S) !!((S)->aCSR[0] & 0x0020) /**< Receive On */
363#define CSR_INEA(S) !!((S)->aCSR[0] & 0x0040) /**< Interrupt Enable */
364#define CSR_LAPPEN(S) !!((S)->aCSR[3] & 0x0020) /**< Look Ahead Packet Processing Enable */
365#define CSR_DXSUFLO(S) !!((S)->aCSR[3] & 0x0040) /**< Disable Transmit Stop on Underflow error */
366#define CSR_ASTRP_RCV(S) !!((S)->aCSR[4] & 0x0400) /**< Auto Strip Receive */
367#define CSR_DPOLL(S) !!((S)->aCSR[4] & 0x1000) /**< Disable Transmit Polling */
368#define CSR_SPND(S) !!((S)->aCSR[5] & 0x0001) /**< Suspend */
369#define CSR_LTINTEN(S) !!((S)->aCSR[5] & 0x4000) /**< Last Transmit Interrupt Enable */
370#define CSR_TOKINTD(S) !!((S)->aCSR[5] & 0x8000) /**< Transmit OK Interrupt Disable */
371
372#define CSR_STINT !!((S)->aCSR[7] & 0x0800) /**< Software Timer Interrupt */
373#define CSR_STINTE !!((S)->aCSR[7] & 0x0400) /**< Software Timer Interrupt Enable */
374
375#define CSR_DRX(S) !!((S)->aCSR[15] & 0x0001) /**< Disable Receiver */
376#define CSR_DTX(S) !!((S)->aCSR[15] & 0x0002) /**< Disable Transmit */
377#define CSR_LOOP(S) !!((S)->aCSR[15] & 0x0004) /**< Loopback Enable */
378#define CSR_DRCVPA(S) !!((S)->aCSR[15] & 0x2000) /**< Disable Receive Physical Address */
379#define CSR_DRCVBC(S) !!((S)->aCSR[15] & 0x4000) /**< Disable Receive Broadcast */
380#define CSR_PROM(S) !!((S)->aCSR[15] & 0x8000) /**< Promiscuous Mode */
381
382#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
383#error fix macros (and more in this file) for big-endian machines
384#endif
385
386#define CSR_IADR(S) (*(uint32_t*)((S)->aCSR + 1)) /**< Initialization Block Address */
387#define CSR_CRBA(S) (*(uint32_t*)((S)->aCSR + 18)) /**< Current Receive Buffer Address */
388#define CSR_CXBA(S) (*(uint32_t*)((S)->aCSR + 20)) /**< Current Transmit Buffer Address */
389#define CSR_NRBA(S) (*(uint32_t*)((S)->aCSR + 22)) /**< Next Receive Buffer Address */
390#define CSR_BADR(S) (*(uint32_t*)((S)->aCSR + 24)) /**< Base Address of Receive Ring */
391#define CSR_NRDA(S) (*(uint32_t*)((S)->aCSR + 26)) /**< Next Receive Descriptor Address */
392#define CSR_CRDA(S) (*(uint32_t*)((S)->aCSR + 28)) /**< Current Receive Descriptor Address */
393#define CSR_BADX(S) (*(uint32_t*)((S)->aCSR + 30)) /**< Base Address of Transmit Descriptor */
394#define CSR_NXDA(S) (*(uint32_t*)((S)->aCSR + 32)) /**< Next Transmit Descriptor Address */
395#define CSR_CXDA(S) (*(uint32_t*)((S)->aCSR + 34)) /**< Current Transmit Descriptor Address */
396#define CSR_NNRD(S) (*(uint32_t*)((S)->aCSR + 36)) /**< Next Next Receive Descriptor Address */
397#define CSR_NNXD(S) (*(uint32_t*)((S)->aCSR + 38)) /**< Next Next Transmit Descriptor Address */
398#define CSR_CRBC(S) ((S)->aCSR[40]) /**< Current Receive Byte Count */
399#define CSR_CRST(S) ((S)->aCSR[41]) /**< Current Receive Status */
400#define CSR_CXBC(S) ((S)->aCSR[42]) /**< Current Transmit Byte Count */
401#define CSR_CXST(S) ((S)->aCSR[43]) /**< Current transmit status */
402#define CSR_NRBC(S) ((S)->aCSR[44]) /**< Next Receive Byte Count */
403#define CSR_NRST(S) ((S)->aCSR[45]) /**< Next Receive Status */
404#define CSR_POLL(S) ((S)->aCSR[46]) /**< Transmit Poll Time Counter */
405#define CSR_PINT(S) ((S)->aCSR[47]) /**< Transmit Polling Interval */
406#define CSR_PXDA(S) (*(uint32_t*)((S)->aCSR + 60)) /**< Previous Transmit Descriptor Address*/
407#define CSR_PXBC(S) ((S)->aCSR[62]) /**< Previous Transmit Byte Count */
408#define CSR_PXST(S) ((S)->aCSR[63]) /**< Previous Transmit Status */
409#define CSR_NXBA(S) (*(uint32_t*)((S)->aCSR + 64)) /**< Next Transmit Buffer Address */
410#define CSR_NXBC(S) ((S)->aCSR[66]) /**< Next Transmit Byte Count */
411#define CSR_NXST(S) ((S)->aCSR[67]) /**< Next Transmit Status */
412#define CSR_RCVRC(S) ((S)->aCSR[72]) /**< Receive Descriptor Ring Counter */
413#define CSR_XMTRC(S) ((S)->aCSR[74]) /**< Transmit Descriptor Ring Counter */
414#define CSR_RCVRL(S) ((S)->aCSR[76]) /**< Receive Descriptor Ring Length */
415#define CSR_XMTRL(S) ((S)->aCSR[78]) /**< Transmit Descriptor Ring Length */
416#define CSR_MISSC(S) ((S)->aCSR[112]) /**< Missed Frame Count */
417
418#define PHYSADDR(S,A) ((A) | (S)->GCUpperPhys)
419
420/* Version for the PCnet/FAST III 79C973 card */
421#define CSR_VERSION_LOW_79C973 0x5003 /* the lower two bits must be 11b for AMD */
422#define CSR_VERSION_LOW_79C970A 0x1003 /* the lower two bits must be 11b for AMD */
423#define CSR_VERSION_HIGH 0x0262
424
425/** @todo All structs: big endian? */
426
427struct INITBLK16
428{
429 uint16_t mode; /**< copied into csr15 */
430 uint16_t padr1; /**< MAC 0..15 */
431 uint16_t padr2; /**< MAC 16..32 */
432 uint16_t padr3; /**< MAC 33..47 */
433 uint16_t ladrf1; /**< logical address filter 0..15 */
434 uint16_t ladrf2; /**< logical address filter 16..31 */
435 uint16_t ladrf3; /**< logical address filter 32..47 */
436 uint16_t ladrf4; /**< logical address filter 48..63 */
437 uint32_t rdra:24; /**< address of receive descriptor ring */
438 uint32_t res1:5; /**< reserved */
439 uint32_t rlen:3; /**< number of receive descriptor ring entries */
440 uint32_t tdra:24; /**< address of transmit descriptor ring */
441 uint32_t res2:5; /**< reserved */
442 uint32_t tlen:3; /**< number of transmit descriptor ring entries */
443};
444AssertCompileSize(INITBLK16, 24);
445
446/** bird: I've changed the type for the bitfields. They should only be 16-bit all together.
447 * frank: I've changed the bitfiled types to uint32_t to prevent compiler warnings. */
448struct INITBLK32
449{
450 uint16_t mode; /**< copied into csr15 */
451 uint16_t res1:4; /**< reserved */
452 uint16_t rlen:4; /**< number of receive descriptor ring entries */
453 uint16_t res2:4; /**< reserved */
454 uint16_t tlen:4; /**< number of transmit descriptor ring entries */
455 uint16_t padr1; /**< MAC 0..15 */
456 uint16_t padr2; /**< MAC 16..31 */
457 uint16_t padr3; /**< MAC 32..47 */
458 uint16_t res3; /**< reserved */
459 uint16_t ladrf1; /**< logical address filter 0..15 */
460 uint16_t ladrf2; /**< logical address filter 16..31 */
461 uint16_t ladrf3; /**< logibal address filter 32..47 */
462 uint16_t ladrf4; /**< logical address filter 48..63 */
463 uint32_t rdra; /**< address of receive descriptor ring */
464 uint32_t tdra; /**< address of transmit descriptor ring */
465};
466AssertCompileSize(INITBLK32, 28);
467
468/** Transmit Message Descriptor */
469typedef struct TMD
470{
471 struct
472 {
473 uint32_t tbadr; /**< transmit buffer address */
474 } tmd0;
475 struct
476 {
477 uint32_t bcnt:12; /**< buffer byte count (two's complement) */
478 uint32_t ones:4; /**< must be 1111b */
479 uint32_t res:7; /**< reserved */
480 uint32_t bpe:1; /**< bus parity error */
481 uint32_t enp:1; /**< end of packet */
482 uint32_t stp:1; /**< start of packet */
483 uint32_t def:1; /**< deferred */
484 uint32_t one:1; /**< exactly one retry was needed to transmit a frame */
485 uint32_t ltint:1; /**< suppress interrupts after successful transmission */
486 uint32_t nofcs:1; /**< when set, the state of DXMTFCS is ignored and
487 transmitter FCS generation is activated. */
488 uint32_t err:1; /**< error occured */
489 uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
490 } tmd1;
491 struct
492 {
493 uint32_t trc:4; /**< transmit retry count */
494 uint32_t res:12; /**< reserved */
495 uint32_t tdr:10; /**< ??? */
496 uint32_t rtry:1; /**< retry error */
497 uint32_t lcar:1; /**< loss of carrier */
498 uint32_t lcol:1; /**< late collision */
499 uint32_t exdef:1; /**< excessive deferral */
500 uint32_t uflo:1; /**< underflow error */
501 uint32_t buff:1; /**< out of buffers (ENP not found) */
502 } tmd2;
503 struct
504 {
505 uint32_t res; /**< reserved for user defined space */
506 } tmd3;
507} TMD;
508AssertCompileSize(TMD, 16);
509
510/** Receive Message Descriptor */
511typedef struct RMD
512{
513 struct
514 {
515 uint32_t rbadr; /**< receive buffer address */
516 } rmd0;
517 struct
518 {
519 uint32_t bcnt:12; /**< buffer byte count (two's complement) */
520 uint32_t ones:4; /**< must be 1111b */
521 uint32_t res:4; /**< reserved */
522 uint32_t bam:1; /**< broadcast address match */
523 uint32_t lafm:1; /**< logical filter address match */
524 uint32_t pam:1; /**< physcial address match */
525 uint32_t bpe:1; /**< bus parity error */
526 uint32_t enp:1; /**< end of packet */
527 uint32_t stp:1; /**< start of packet */
528 uint32_t buff:1; /**< buffer error */
529 uint32_t crc:1; /**< crc error on incoming frame */
530 uint32_t oflo:1; /**< overflow error (lost all or part of incoming frame) */
531 uint32_t fram:1; /**< frame error */
532 uint32_t err:1; /**< error occured */
533 uint32_t own:1; /**< 0=owned by guest driver, 1=owned by controller */
534 } rmd1;
535 struct
536 {
537 uint32_t mcnt:12; /**< message byte count */
538 uint32_t zeros:4; /**< 0000b */
539 uint32_t rpc:8; /**< receive frame tag */
540 uint32_t rcc:8; /**< receive frame tag + reserved */
541 } rmd2;
542 struct
543 {
544 uint32_t res; /**< reserved for user defined space */
545 } rmd3;
546} RMD;
547AssertCompileSize(RMD, 16);
548
549
550#ifndef VBOX_DEVICE_STRUCT_TESTCASE
551/*******************************************************************************
552* Internal Functions *
553*******************************************************************************/
554#define PRINT_TMD(T) Log2(( \
555 "TMD0 : TBADR=%#010x\n" \
556 "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
557 "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
558 " BPE=%d, BCNT=%d\n" \
559 "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
560 "LCA=%d, RTR=%d,\n" \
561 " TDR=%d, TRC=%d\n", \
562 (T)->tmd0.tbadr, \
563 (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \
564 (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \
565 (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \
566 4096-(T)->tmd1.bcnt, \
567 (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
568 (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
569 (T)->tmd2.tdr, (T)->tmd2.trc))
570
571#define PRINT_RMD(R) Log2(( \
572 "RMD0 : RBADR=%#010x\n" \
573 "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
574 "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
575 "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
576 "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
577 (R)->rmd0.rbadr, \
578 (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \
579 (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \
580 (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \
581 (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \
582 (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \
583 (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
584 (R)->rmd2.zeros))
585
586#if defined(PCNET_QUEUE_SEND_PACKETS) && defined(IN_RING3)
587static int pcnetSyncTransmit(PCNetState *pData);
588#endif
589
590/**
591 * Load transmit message descriptor
592 * Make sure we read the own flag first.
593 *
594 * @param pData adapter private data
595 * @param addr physical address of the descriptor
596 * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor
597 * @return true if we own the descriptor, false otherwise
598 */
599DECLINLINE(bool) pcnetTmdLoad(PCNetState *pData, TMD *tmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
600{
601 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
602 uint8_t ownbyte;
603
604 if (pData->fPrivIfEnabled)
605 {
606 /* RX/TX descriptors shared between host and guest => direct copy */
607 uint8_t *pv = (uint8_t*)pData->CTXSUFF(pSharedMMIO)
608 + (addr - pData->GCTDRA)
609 + pData->CTXSUFF(pSharedMMIO)->V.V1.offTxDescriptors;
610 if (!(pv[7] & 0x80) && fRetIfNotOwn)
611 return false;
612 memcpy(tmd, pv, 16);
613 return true;
614 }
615 else if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
616 {
617 uint16_t xda[4];
618
619 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
620 if (!(ownbyte & 0x80) && fRetIfNotOwn)
621 return false;
622 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
623 ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
624 ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
625 ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;
626 ((uint32_t *)tmd)[3] = 0;
627 }
628 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
629 {
630 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
631 if (!(ownbyte & 0x80) && fRetIfNotOwn)
632 return false;
633 PDMDevHlpPhysRead(pDevIns, addr, (void*)tmd, 16);
634 }
635 else
636 {
637 uint32_t xda[4];
638 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
639 if (!(ownbyte & 0x80) && fRetIfNotOwn)
640 return false;
641 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
642 ((uint32_t *)tmd)[0] = xda[2];
643 ((uint32_t *)tmd)[1] = xda[1];
644 ((uint32_t *)tmd)[2] = xda[0];
645 ((uint32_t *)tmd)[3] = xda[3];
646 }
647 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
648#ifdef DEBUG
649 if (tmd->tmd1.own == 1 && !(ownbyte & 0x80))
650 Log(("pcnetTmdLoad: own bit flipped while reading!!\n"));
651#endif
652 if (!(ownbyte & 0x80))
653 tmd->tmd1.own = 0;
654
655 return !!tmd->tmd1.own;
656}
657
658/**
659 * Store transmit message descriptor and hand it over to the host (the VM guest).
660 * Make sure that all data are transmitted before we clear the own flag.
661 */
662DECLINLINE(void) pcnetTmdStorePassHost(PCNetState *pData, TMD *tmd, RTGCPHYS32 addr)
663{
664 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTmdStore), a);
665 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
666 if (pData->fPrivIfEnabled)
667 {
668 /* RX/TX descriptors shared between host and guest => direct copy */
669 uint8_t *pv = (uint8_t*)pData->CTXSUFF(pSharedMMIO)
670 + (addr - pData->GCTDRA)
671 + pData->CTXSUFF(pSharedMMIO)->V.V1.offTxDescriptors;
672 memcpy(pv, tmd, 16);
673 pv[7] &= ~0x80;
674 }
675 else if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
676 {
677 uint16_t xda[4];
678 xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
679 xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00);
680 xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
681 xda[3] = ((uint32_t *)tmd)[2] >> 16;
682 xda[1] |= 0x8000;
683 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
684 xda[1] &= ~0x8000;
685 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)xda + 3, 1);
686 }
687 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
688 {
689 ((uint32_t*)tmd)[1] |= 0x80000000;
690 PDMDevHlpPhysWrite(pDevIns, addr, (void*)tmd, 16);
691 ((uint32_t*)tmd)[1] &= ~0x80000000;
692 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)tmd + 7, 1);
693 }
694 else
695 {
696 uint32_t xda[4];
697 xda[0] = ((uint32_t *)tmd)[2];
698 xda[1] = ((uint32_t *)tmd)[1];
699 xda[2] = ((uint32_t *)tmd)[0];
700 xda[3] = ((uint32_t *)tmd)[3];
701 xda[1] |= 0x80000000;
702 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
703 xda[1] &= ~0x80000000;
704 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)xda + 7, 1);
705 }
706 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTmdStore), a);
707}
708
709/**
710 * Load receive message descriptor
711 * Make sure we read the own flag first.
712 *
713 * @param pData adapter private data
714 * @param addr physical address of the descriptor
715 * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor
716 * @return true if we own the descriptor, false otherwise
717 */
718DECLINLINE(int) pcnetRmdLoad(PCNetState *pData, RMD *rmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
719{
720 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
721 uint8_t ownbyte;
722
723 if (pData->fPrivIfEnabled)
724 {
725 /* RX/TX descriptors shared between host and guest => direct copy */
726 uint8_t *pb = (uint8_t*)pData->CTXSUFF(pSharedMMIO)
727 + (addr - pData->GCRDRA)
728 + pData->CTXSUFF(pSharedMMIO)->V.V1.offRxDescriptors;
729 if (!(pb[7] & 0x80) && fRetIfNotOwn)
730 return false;
731 memcpy(rmd, pb, 16);
732 return true;
733 }
734 else if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
735 {
736 uint16_t rda[4];
737 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
738 if ((!ownbyte & 0x80) && fRetIfNotOwn)
739 return false;
740 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
741 ((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16);
742 ((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16);
743 ((uint32_t *)rmd)[2] = (uint32_t)rda[3];
744 ((uint32_t *)rmd)[3] = 0;
745 }
746 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
747 {
748 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
749 if ((!ownbyte & 0x80) && fRetIfNotOwn)
750 return false;
751 PDMDevHlpPhysRead(pDevIns, addr, (void*)rmd, 16);
752 }
753 else
754 {
755 uint32_t rda[4];
756 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
757 if ((!ownbyte & 0x80) && fRetIfNotOwn)
758 return false;
759 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
760 ((uint32_t *)rmd)[0] = rda[2];
761 ((uint32_t *)rmd)[1] = rda[1];
762 ((uint32_t *)rmd)[2] = rda[0];
763 ((uint32_t *)rmd)[3] = rda[3];
764 }
765 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
766#ifdef DEBUG
767 if (rmd->rmd1.own == 1 && !(ownbyte & 0x80))
768 Log(("pcnetRmdLoad: own bit flipped while reading!!\n"));
769#endif
770 if (!(ownbyte & 0x80))
771 rmd->rmd1.own = 0;
772
773 return !!rmd->rmd1.own;
774}
775
776/**
777 * Store receive message descriptor and hand it over to the host (the VM guest).
778 * Make sure that all data are transmitted before we clear the own flag.
779 */
780DECLINLINE(void) pcnetRmdStorePassHost(PCNetState *pData, RMD *rmd, RTGCPHYS32 addr)
781{
782 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
783 if (pData->fPrivIfEnabled)
784 {
785 /* RX/TX descriptors shared between host and guest => direct copy */
786 uint8_t *pv = (uint8_t*)pData->CTXSUFF(pSharedMMIO)
787 + (addr - pData->GCRDRA)
788 + pData->CTXSUFF(pSharedMMIO)->V.V1.offRxDescriptors;
789 memcpy(pv, rmd, 16);
790 pv[7] &= ~0x80;
791 }
792 else if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
793 {
794 uint16_t rda[4];
795 rda[0] = ((uint32_t *)rmd)[0] & 0xffff;
796 rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00);
797 rda[2] = ((uint32_t *)rmd)[1] & 0xffff;
798 rda[3] = ((uint32_t *)rmd)[2] & 0xffff;
799 rda[1] |= 0x8000;
800 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
801 rda[1] &= ~0x8000;
802 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)rda + 3, 1);
803 }
804 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
805 {
806 ((uint32_t*)rmd)[1] |= 0x80000000;
807 PDMDevHlpPhysWrite(pDevIns, addr, (void*)rmd, 16);
808 ((uint32_t*)rmd)[1] &= ~0x80000000;
809 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rmd + 7, 1);
810 }
811 else
812 {
813 uint32_t rda[4];
814 rda[0] = ((uint32_t *)rmd)[2];
815 rda[1] = ((uint32_t *)rmd)[1];
816 rda[2] = ((uint32_t *)rmd)[0];
817 rda[3] = ((uint32_t *)rmd)[3];
818 rda[1] |= 0x80000000;
819 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
820 rda[1] &= ~0x80000000;
821 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rda + 7, 1);
822 }
823}
824
825/** Checks if it's a bad (as in invalid) RMD.*/
826#define IS_RMD_BAD(rmd) ((rmd).rmd1.ones != 15 || (rmd).rmd2.zeros != 0)
827
828/** The network card is the owner of the RDTE/TDTE, actually it is this driver */
829#define CARD_IS_OWNER(desc) (((desc) & 0x8000))
830
831/** The host is the owner of the RDTE/TDTE -- actually the VM guest. */
832#define HOST_IS_OWNER(desc) (!((desc) & 0x8000))
833
834#ifndef ETHER_IS_MULTICAST /* Net/Open BSD macro it seems */
835#define ETHER_IS_MULTICAST(a) ((*(uint8_t *)(a)) & 1)
836#endif
837
838#define ETHER_ADDR_LEN ETH_ALEN
839#define ETH_ALEN 6
840#pragma pack(1)
841struct ether_header
842{
843 uint8_t ether_dhost[ETH_ALEN]; /**< destination ethernet address */
844 uint8_t ether_shost[ETH_ALEN]; /**< source ethernet address */
845 uint16_t ether_type; /**< packet type ID field */
846};
847#pragma pack()
848
849#define PRINT_PKTHDR(BUF) do { \
850 struct ether_header *hdr = (struct ether_header *)(BUF); \
851 Log(("#%d packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
852 "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
853 "type=%#06x (bcast=%d)\n", PCNET_INST_NR, \
854 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
855 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
856 hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
857 hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
858 htons(hdr->ether_type), \
859 !!ETHER_IS_MULTICAST(hdr->ether_dhost))); \
860} while (0)
861
862
863#ifdef IN_RING3
864
865/**
866 * Initialize the shared memory for the private guest interface.
867 *
868 * @note Changing this layout will break SSM for guests using the private guest interface!
869 */
870static void pcnetInitSharedMemory(PCNetState *pData)
871{
872 /* Clear the entire block for pcnetReset usage. */
873 memset(pData->pSharedMMIOHC, 0, PCNET_GUEST_SHARED_MEMORY_SIZE);
874
875 pData->pSharedMMIOHC->u32Version = PCNET_GUEST_INTERFACE_VERSION;
876 uint32_t off = 2048; /* Leave some space for more fields within the header */
877
878 /*
879 * The Descriptor arrays.
880 */
881 pData->pSharedMMIOHC->V.V1.offTxDescriptors = off;
882 off = RT_ALIGN(off + PCNET_GUEST_TX_DESCRIPTOR_SIZE * PCNET_GUEST_MAX_TX_DESCRIPTORS, 32);
883
884 pData->pSharedMMIOHC->V.V1.offRxDescriptors = off;
885 off = RT_ALIGN(off + PCNET_GUEST_RX_DESCRIPTOR_SIZE * PCNET_GUEST_MAX_RX_DESCRIPTORS, 32);
886
887 /* Make sure all the descriptors are mapped into HMA space (and later ring-0). The 8192
888 bytes limit is hardcoded in the PDMDevHlpMMHyperMapMMIO2 call down in pcnetConstruct. */
889 AssertRelease(off <= 8192);
890
891 /*
892 * The buffer arrays.
893 */
894#if 0
895 /* Don't allocate TX buffers since Windows guests cannot use it */
896 pData->pSharedMMIOHC->V.V1.offTxBuffers = off;
897 off = RT_ALIGN(off + PCNET_GUEST_NIC_BUFFER_SIZE * PCNET_GUEST_MAX_TX_DESCRIPTORS, 32);
898#endif
899
900 pData->pSharedMMIOHC->V.V1.offRxBuffers = off;
901 pData->pSharedMMIOHC->fFlags = PCNET_GUEST_FLAGS_ADMIT_HOST;
902 off = RT_ALIGN(off + PCNET_GUEST_NIC_BUFFER_SIZE * PCNET_GUEST_MAX_RX_DESCRIPTORS, 32);
903 AssertRelease(off <= PCNET_GUEST_SHARED_MEMORY_SIZE);
904
905 /* Update the header with the final size. */
906 pData->pSharedMMIOHC->cbUsed = off;
907}
908
909#define MULTICAST_FILTER_LEN 8
910
911DECLINLINE(uint32_t) lnc_mchash(const uint8_t *ether_addr)
912{
913#define LNC_POLYNOMIAL 0xEDB88320UL
914 uint32_t crc = 0xFFFFFFFF;
915 int idx, bit;
916 uint8_t data;
917
918 for (idx = 0; idx < ETHER_ADDR_LEN; idx++)
919 {
920 for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++)
921 {
922 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
923 data >>= 1;
924 }
925 }
926 return crc;
927#undef LNC_POLYNOMIAL
928}
929
930#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
931
932/* generated using the AUTODIN II polynomial
933 * x^32 + x^26 + x^23 + x^22 + x^16 +
934 * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
935 */
936static const uint32_t crctab[256] =
937{
938 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
939 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
940 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
941 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
942 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
943 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
944 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
945 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
946 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
947 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
948 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
949 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
950 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
951 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
952 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
953 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
954 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
955 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
956 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
957 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
958 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
959 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
960 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
961 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
962 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
963 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
964 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
965 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
966 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
967 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
968 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
969 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
970 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
971 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
972 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
973 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
974 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
975 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
976 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
977 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
978 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
979 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
980 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
981 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
982 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
983 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
984 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
985 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
986 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
987 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
988 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
989 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
990 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
991 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
992 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
993 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
994 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
995 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
996 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
997 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
998 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
999 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1000 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1001 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1002};
1003
1004DECLINLINE(int) padr_match(PCNetState *pData, const uint8_t *buf, int size)
1005{
1006 struct ether_header *hdr = (struct ether_header *)buf;
1007 int result;
1008#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(PCNET_DEBUG_MATCH)
1009 result = !CSR_DRCVPA(pData) && !memcmp(hdr->ether_dhost, pData->aCSR + 12, 6);
1010#else
1011 uint8_t padr[6];
1012 padr[0] = pData->aCSR[12] & 0xff;
1013 padr[1] = pData->aCSR[12] >> 8;
1014 padr[2] = pData->aCSR[13] & 0xff;
1015 padr[3] = pData->aCSR[13] >> 8;
1016 padr[4] = pData->aCSR[14] & 0xff;
1017 padr[5] = pData->aCSR[14] >> 8;
1018 result = !CSR_DRCVPA(pData) && !memcmp(hdr->ether_dhost, padr, 6);
1019#endif
1020
1021#ifdef PCNET_DEBUG_MATCH
1022 Log(("#%d packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
1023 "padr=%02x:%02x:%02x:%02x:%02x:%02x => %d\n", PCNET_INST_NR,
1024 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
1025 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
1026 padr[0],padr[1],padr[2],padr[3],padr[4],padr[5], result));
1027#endif
1028 return result;
1029}
1030
1031DECLINLINE(int) padr_bcast(PCNetState *pData, const uint8_t *buf, int size)
1032{
1033 static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1034 struct ether_header *hdr = (struct ether_header *)buf;
1035 int result = !CSR_DRCVBC(pData) && !memcmp(hdr->ether_dhost, aBCAST, 6);
1036#ifdef PCNET_DEBUG_MATCH
1037 Log(("#%d padr_bcast result=%d\n", PCNET_INST_NR, result));
1038#endif
1039 return result;
1040}
1041
1042static int ladr_match(PCNetState *pData, const uint8_t *buf, int size)
1043{
1044 struct ether_header *hdr = (struct ether_header *)buf;
1045 if (RT_UNLIKELY(hdr->ether_dhost[0] & 0x01) && ((uint64_t *)&pData->aCSR[8])[0] != 0LL)
1046 {
1047 int index;
1048#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
1049 index = lnc_mchash(hdr->ether_dhost) >> 26;
1050 return ((uint8_t*)(pData->aCSR + 8))[index >> 3] & (1 << (index & 7));
1051#else
1052 uint8_t ladr[8];
1053 ladr[0] = pData->aCSR[8] & 0xff;
1054 ladr[1] = pData->aCSR[8] >> 8;
1055 ladr[2] = pData->aCSR[9] & 0xff;
1056 ladr[3] = pData->aCSR[9] >> 8;
1057 ladr[4] = pData->aCSR[10] & 0xff;
1058 ladr[5] = pData->aCSR[10] >> 8;
1059 ladr[6] = pData->aCSR[11] & 0xff;
1060 ladr[7] = pData->aCSR[11] >> 8;
1061 index = lnc_mchash(hdr->ether_dhost) >> 26;
1062 return (ladr[index >> 3] & (1 << (index & 7)));
1063#endif
1064 }
1065 return 0;
1066}
1067
1068#endif /* IN_RING3 */
1069
1070/**
1071 * Get the receive descriptor ring address with a given index.
1072 */
1073DECLINLINE(RTGCPHYS32) pcnetRdraAddr(PCNetState *pData, int idx)
1074{
1075 return pData->GCRDRA + ((CSR_RCVRL(pData) - idx) << pData->iLog2DescSize);
1076}
1077
1078/**
1079 * Get the transmit descriptor ring address with a given index.
1080 */
1081DECLINLINE(RTGCPHYS32) pcnetTdraAddr(PCNetState *pData, int idx)
1082{
1083 return pData->GCTDRA + ((CSR_XMTRL(pData) - idx) << pData->iLog2DescSize);
1084}
1085
1086__BEGIN_DECLS
1087PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
1088 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1089PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
1090 RTIOPORT Port, uint32_t u32, unsigned cb);
1091PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
1092 RTIOPORT Port, uint32_t u32, unsigned cb);
1093PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
1094 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1095PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
1096 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1097PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
1098 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1099#ifndef IN_RING3
1100DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1101 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
1102#endif
1103__END_DECLS
1104
1105#undef htonl
1106#define htonl(x) ASMByteSwapU32(x)
1107#undef htons
1108#define htons(x) ( (((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8) )
1109
1110static void pcnetPollRxTx(PCNetState *pData);
1111static void pcnetPollTimer(PCNetState *pData);
1112static void pcnetUpdateIrq(PCNetState *pData);
1113static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP);
1114static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val);
1115
1116
1117#ifdef PCNET_NO_POLLING
1118# ifndef IN_RING3
1119
1120/**
1121 * #PF Virtual Handler callback for Guest write access to the ring descriptor page(pData)
1122 *
1123 * @return VBox status code (appropriate for trap handling and GC return).
1124 * @param pVM VM Handle.
1125 * @param uErrorCode CPU Error code.
1126 * @param pRegFrame Trap register frame.
1127 * @param pvFault The fault address (cr2).
1128 * @param GCPhysFault The GC physical address corresponding to pvFault.
1129 * @param pvUser User argument.
1130 */
1131DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1132 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1133{
1134 PCNetState *pData = (PCNetState *)pvUser;
1135
1136 Log(("#%d pcnetHandleRingWriteGC: write to %#010x\n", PCNET_INST_NR, GCPhysFault));
1137
1138 uint32_t cb;
1139 int rc = CTXALLSUFF(pData->pfnEMInterpretInstruction)(pVM, pRegFrame, pvFault, &cb);
1140 if (VBOX_SUCCESS(rc) && cb)
1141 {
1142 if ( (GCPhysFault >= pData->GCTDRA && GCPhysFault + cb < pcnetTdraAddr(pData, 0))
1143#ifdef PCNET_MONITOR_RECEIVE_RING
1144 || (GCPhysFault >= pData->GCRDRA && GCPhysFault + cb < pcnetRdraAddr(pData, 0))
1145#endif
1146 )
1147 {
1148 uint32_t offsetTDRA = (GCPhysFault - pData->GCTDRA);
1149
1150 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1151 if (VBOX_SUCCESS(rc))
1152 {
1153 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWrite)); ;
1154
1155 /* Check if we can do something now */
1156 pcnetPollRxTx(pData);
1157 pcnetUpdateIrq(pData);
1158
1159 PDMCritSectLeave(&pData->CritSect);
1160 return VINF_SUCCESS;
1161 }
1162 }
1163 else
1164 {
1165 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteOutsideRange)); ;
1166 return VINF_SUCCESS; /* outside of the ring range */
1167 }
1168 }
1169 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteFailed)); ;
1170 return VINF_IOM_HC_MMIO_WRITE; /* handle in ring3 */
1171}
1172
1173# else /* IN_RING3 */
1174
1175/**
1176 * #PF Handler callback for physical access handler ranges (MMIO among others) in HC.
1177 *
1178 * The handler can not raise any faults, it's mainly for monitoring write access
1179 * to certain pages.
1180 *
1181 * @returns VINF_SUCCESS if the handler have carried out the operation.
1182 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1183 * @param pVM VM Handle.
1184 * @param GCPhys The physical address the guest is writing to.
1185 * @param pvPhys The HC mapping of that address.
1186 * @param pvBuf What the guest is reading/writing.
1187 * @param cbBuf How much it's reading/writing.
1188 * @param enmAccessType The access type.
1189 * @param pvUser User argument.
1190 */
1191static DECLCALLBACK(int) pcnetHandleRingWrite(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf,
1192 size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1193{
1194 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
1195 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1196
1197 Log(("#%d pcnetHandleRingWrite: write to %#010x\n", PCNET_INST_NR, GCPhys));
1198#ifdef VBOX_WITH_STATISTICS
1199 STAM_COUNTER_INC(&CTXSUFF(pData->StatRingWrite));
1200 if (GCPhys >= pData->GCRDRA && GCPhys < pcnetRdraAddr(pData, 0))
1201 STAM_COUNTER_INC(&pData->StatRCVRingWrite);
1202 else if (GCPhys >= pData->GCTDRA && GCPhys < pcnetTdraAddr(pData, 0))
1203 STAM_COUNTER_INC(&pData->StatTXRingWrite);
1204#endif
1205 /* Perform the actual write */
1206 memcpy((char *)pvPhys, pvBuf, cbBuf);
1207
1208 /* Writes done by our code don't require polling of course */
1209 if (PDMCritSectIsOwner(&pData->CritSect) == false)
1210 {
1211 if ( (GCPhys >= pData->GCTDRA && GCPhys + cbBuf < pcnetTdraAddr(pData, 0))
1212#ifdef PCNET_MONITOR_RECEIVE_RING
1213 || (GCPhys >= pData->GCRDRA && GCPhys + cbBuf < pcnetRdraAddr(pData, 0))
1214#endif
1215 )
1216 {
1217 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1218 AssertReleaseRC(rc);
1219 /* Check if we can do something now */
1220 pcnetPollRxTx(pData);
1221 pcnetUpdateIrq(pData);
1222 PDMCritSectLeave(&pData->CritSect);
1223 }
1224 }
1225 return VINF_SUCCESS;
1226}
1227# endif /* !IN_RING3 */
1228#endif /* PCNET_NO_POLLING */
1229
1230static void pcnetSoftReset(PCNetState *pData)
1231{
1232 Log(("#%d pcnetSoftReset:\n", PCNET_INST_NR));
1233
1234 pData->u32Lnkst = 0x40;
1235 pData->GCRDRA = 0;
1236 pData->GCTDRA = 0;
1237 pData->u32RAP = 0;
1238
1239 pData->aBCR[BCR_BSBC] &= ~0x0080;
1240
1241 pData->aCSR[0] = 0x0004;
1242 pData->aCSR[3] = 0x0000;
1243 pData->aCSR[4] = 0x0115;
1244 pData->aCSR[5] = 0x0000;
1245 pData->aCSR[6] = 0x0000;
1246 pData->aCSR[8] = 0;
1247 pData->aCSR[9] = 0;
1248 pData->aCSR[10] = 0;
1249 pData->aCSR[11] = 0;
1250 pData->aCSR[12] = RT_LE2H_U16(((uint16_t *)&pData->aPROM[0])[0]);
1251 pData->aCSR[13] = RT_LE2H_U16(((uint16_t *)&pData->aPROM[0])[1]);
1252 pData->aCSR[14] = RT_LE2H_U16(((uint16_t *)&pData->aPROM[0])[2]);
1253 pData->aCSR[15] &= 0x21c4;
1254 CSR_RCVRC(pData) = 1;
1255 CSR_XMTRC(pData) = 1;
1256 CSR_RCVRL(pData) = 1;
1257 CSR_XMTRL(pData) = 1;
1258 pData->aCSR[80] = 0x1410;
1259 pData->aCSR[88] = pData->fAm79C973 ? CSR_VERSION_LOW_79C973 : CSR_VERSION_LOW_79C970A;
1260 pData->aCSR[89] = CSR_VERSION_HIGH;
1261 pData->aCSR[94] = 0x0000;
1262 pData->aCSR[100] = 0x0200;
1263 pData->aCSR[103] = 0x0105;
1264 pData->aCSR[103] = 0x0105;
1265 CSR_MISSC(pData) = 0;
1266 pData->aCSR[114] = 0x0000;
1267 pData->aCSR[122] = 0x0000;
1268 pData->aCSR[124] = 0x0000;
1269}
1270
1271/**
1272 * Check if we have to send an interrupt to the guest. An interrupt can occur on
1273 * - csr0 (written quite often)
1274 * - csr4 (only written by pcnetSoftReset(), pcnetStop() or by the guest driver)
1275 * - csr5 (only written by pcnetSoftReset(), pcnetStop or by the driver guest)
1276 */
1277static void pcnetUpdateIrq(PCNetState *pData)
1278{
1279 register int iISR = 0;
1280 register uint16_t csr0 = pData->aCSR[0];
1281
1282 csr0 &= ~0x0080; /* clear INTR */
1283
1284 STAM_PROFILE_ADV_START(&pData->StatInterrupt, a);
1285
1286 /* Linux guests set csr4=0x0915
1287 * W2k guests set csr3=0x4940 (disable BABL, MERR, IDON, DXSUFLO */
1288
1289#if 1
1290 if ( ( (csr0 & ~pData->aCSR[3]) & 0x5f00)
1291 || (((pData->aCSR[4]>>1) & ~pData->aCSR[4]) & 0x0115)
1292 || (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0048))
1293#else
1294 if ( ( !(pData->aCSR[3] & 0x4000) && !!(csr0 & 0x4000)) /* BABL */
1295 ||( !(pData->aCSR[3] & 0x1000) && !!(csr0 & 0x1000)) /* MISS */
1296 ||( !(pData->aCSR[3] & 0x0100) && !!(csr0 & 0x0100)) /* IDON */
1297 ||( !(pData->aCSR[3] & 0x0200) && !!(csr0 & 0x0200)) /* TINT */
1298 ||( !(pData->aCSR[3] & 0x0400) && !!(csr0 & 0x0400)) /* RINT */
1299 ||( !(pData->aCSR[3] & 0x0800) && !!(csr0 & 0x0800)) /* MERR */
1300 ||( !(pData->aCSR[4] & 0x0001) && !!(pData->aCSR[4] & 0x0002)) /* JAB */
1301 ||( !(pData->aCSR[4] & 0x0004) && !!(pData->aCSR[4] & 0x0008)) /* TXSTRT */
1302 ||( !(pData->aCSR[4] & 0x0010) && !!(pData->aCSR[4] & 0x0020)) /* RCVO */
1303 ||( !(pData->aCSR[4] & 0x0100) && !!(pData->aCSR[4] & 0x0200)) /* MFCO */
1304 ||(!!(pData->aCSR[5] & 0x0040) && !!(pData->aCSR[5] & 0x0080)) /* EXDINT */
1305 ||(!!(pData->aCSR[5] & 0x0008) && !!(pData->aCSR[5] & 0x0010)) /* MPINT */)
1306#endif
1307 {
1308 iISR = !!(csr0 & 0x0040); /* CSR_INEA */
1309 csr0 |= 0x0080; /* set INTR */
1310 }
1311
1312#ifdef VBOX
1313 if (pData->aCSR[4] & 0x0080) /* UINTCMD */
1314 {
1315 pData->aCSR[4] &= ~0x0080; /* clear UINTCMD */
1316 pData->aCSR[4] |= 0x0040; /* set UINT */
1317 Log(("#%d user int\n", PCNET_INST_NR));
1318 }
1319 if (pData->aCSR[4] & csr0 & 0x0040 /* CSR_INEA */)
1320 {
1321 csr0 |= 0x0080; /* set INTR */
1322 iISR = 1;
1323 }
1324#else /* !VBOX */
1325 if (!!(pData->aCSR[4] & 0x0080) && CSR_INEA(pData)) /* UINTCMD */
1326 {
1327 pData->aCSR[4] &= ~0x0080;
1328 pData->aCSR[4] |= 0x0040; /* set UINT */
1329 csr0 |= 0x0080; /* set INTR */
1330 iISR = 1;
1331 Log(("#%d user int\n", PCNET_INST_NR));
1332 }
1333#endif /* !VBOX */
1334
1335#if 1
1336 if (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0500)
1337#else
1338 if ( (!!(pData->aCSR[5] & 0x0400) && !!(pData->aCSR[5] & 0x0800)) /* SINT */
1339 ||(!!(pData->aCSR[5] & 0x0100) && !!(pData->aCSR[5] & 0x0200)) /* SLPINT */)
1340#endif
1341 {
1342 iISR = 1;
1343 csr0 |= 0x0080; /* INTR */
1344 }
1345
1346 if ((pData->aCSR[7] & 0x0C00) == 0x0C00) /* STINT + STINTE */
1347 iISR = 1;
1348
1349 pData->aCSR[0] = csr0;
1350
1351 Log2(("#%d set irq iISR=%d\n", PCNET_INST_NR, iISR));
1352
1353 /* normal path is to _not_ change the IRQ status */
1354 if (RT_UNLIKELY(iISR != pData->iISR))
1355 {
1356 Log(("#%d INTA=%d\n", PCNET_INST_NR, iISR));
1357 PDMDevHlpPCISetIrqNoWait(PCNETSTATE_2_DEVINS(pData), 0, iISR);
1358 pData->iISR = iISR;
1359 }
1360 STAM_PROFILE_ADV_STOP(&pData->StatInterrupt, a);
1361}
1362
1363/**
1364 * Enable/disable the private guest interface.
1365 */
1366static void pcnetEnablePrivateIf(PCNetState *pData)
1367{
1368 bool fPrivIfEnabled = pData->pSharedMMIOHC
1369 && !!(pData->CTXSUFF(pSharedMMIO)->fFlags & PCNET_GUEST_FLAGS_ADMIT_GUEST);
1370 if (fPrivIfEnabled != pData->fPrivIfEnabled)
1371 {
1372 pData->fPrivIfEnabled = fPrivIfEnabled;
1373 LogRel(("PCNet#%d: %s private interface\n", PCNET_INST_NR, fPrivIfEnabled ? "Enabling" : "Disabling"));
1374 }
1375}
1376
1377#ifdef IN_RING3
1378#ifdef PCNET_NO_POLLING
1379static void pcnetUpdateRingHandlers(PCNetState *pData)
1380{
1381 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1382 int rc;
1383
1384 Log(("pcnetUpdateRingHandlers TD %VGp size %#x -> %VGp size %#x\n", pData->TDRAPhysOld, pData->cbTDRAOld, pData->GCTDRA, pcnetTdraAddr(pData, 0)));
1385 Log(("pcnetUpdateRingHandlers RX %VGp size %#x -> %VGp size %#x\n", pData->RDRAPhysOld, pData->cbRDRAOld, pData->GCRDRA, pcnetRdraAddr(pData, 0)));
1386
1387 /** @todo unregister order not correct! */
1388
1389#ifdef PCNET_MONITOR_RECEIVE_RING
1390 if (pData->GCRDRA != pData->RDRAPhysOld || CSR_RCVRL(pData) != pData->cbRDRAOld)
1391 {
1392 if (pData->RDRAPhysOld != 0)
1393 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1394 pData->RDRAPhysOld & ~PAGE_OFFSET_MASK);
1395
1396 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1397 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1398 pData->GCRDRA & ~PAGE_OFFSET_MASK,
1399 RT_ALIGN(pcnetRdraAddr(pData, 0), PAGE_SIZE) - 1,
1400 pcnetHandleRingWrite, pDevIns,
1401 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1402 pData->pDevInsHC->pvInstanceDataHC,
1403 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1404 pData->pDevInsHC->pvInstanceDataGC,
1405 "PCNet receive ring write access handler");
1406 AssertRC(rc);
1407
1408 pData->RDRAPhysOld = pData->GCRDRA;
1409 pData->cbRDRAOld = pcnetRdraAddr(pData, 0);
1410 }
1411#endif /* PCNET_MONITOR_RECEIVE_RING */
1412
1413#ifdef PCNET_MONITOR_RECEIVE_RING
1414 /* 3 possibilities:
1415 * 1) TDRA on different physical page as RDRA
1416 * 2) TDRA completely on same physical page as RDRA
1417 * 3) TDRA & RDRA overlap partly with different physical pages
1418 */
1419 RTGCPHYS32 RDRAPageStart = pData->GCRDRA & ~PAGE_OFFSET_MASK;
1420 RTGCPHYS32 RDRAPageEnd = (pcnetRdraAddr(pData, 0) - 1) & ~PAGE_OFFSET_MASK;
1421 RTGCPHYS32 TDRAPageStart = pData->GCTDRA & ~PAGE_OFFSET_MASK;
1422 RTGCPHYS32 TDRAPageEnd = (pcnetTdraAddr(pData, 0) - 1) & ~PAGE_OFFSET_MASK;
1423
1424 if ( RDRAPageStart > TDRAPageEnd
1425 || TDRAPageStart > RDRAPageEnd)
1426 {
1427#endif /* PCNET_MONITOR_RECEIVE_RING */
1428 /* 1) */
1429 if (pData->GCTDRA != pData->TDRAPhysOld || CSR_XMTRL(pData) != pData->cbTDRAOld)
1430 {
1431 if (pData->TDRAPhysOld != 0)
1432 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1433 pData->TDRAPhysOld & ~PAGE_OFFSET_MASK);
1434
1435 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1436 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1437 pData->GCTDRA & ~PAGE_OFFSET_MASK,
1438 RT_ALIGN(pcnetTdraAddr(pData, 0), PAGE_SIZE) - 1,
1439 pcnetHandleRingWrite, pDevIns,
1440 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1441 pData->pDevInsHC->pvInstanceDataHC,
1442 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1443 pData->pDevInsHC->pvInstanceDataGC,
1444 "PCNet transmit ring write access handler");
1445 AssertRC(rc);
1446
1447 pData->TDRAPhysOld = pData->GCTDRA;
1448 pData->cbTDRAOld = pcnetTdraAddr(pData, 0);
1449 }
1450#ifdef PCNET_MONITOR_RECEIVE_RING
1451 }
1452 else
1453 if ( RDRAPageStart != TDRAPageStart
1454 && ( TDRAPageStart == RDRAPageEnd
1455 || TDRAPageEnd == RDRAPageStart
1456 )
1457 )
1458 {
1459 /* 3) */
1460 AssertFailed();
1461 }
1462 /* else 2) */
1463#endif
1464}
1465#endif /* PCNET_NO_POLLING */
1466
1467static void pcnetInit(PCNetState *pData)
1468{
1469 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1470 Log(("#%d pcnetInit: init_addr=%#010x\n", PCNET_INST_NR, PHYSADDR(pData, CSR_IADR(pData))));
1471
1472 /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
1473 * Software is allowed to write these registers directly. */
1474#define PCNET_INIT() do { \
1475 PDMDevHlpPhysRead(pDevIns, PHYSADDR(pData, CSR_IADR(pData)), \
1476 (uint8_t *)&initblk, sizeof(initblk)); \
1477 pData->aCSR[15] = RT_LE2H_U16(initblk.mode); \
1478 CSR_RCVRL(pData) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
1479 CSR_XMTRL(pData) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
1480 pData->aCSR[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
1481 pData->aCSR[ 8] = RT_LE2H_U16(initblk.ladrf1); \
1482 pData->aCSR[ 9] = RT_LE2H_U16(initblk.ladrf2); \
1483 pData->aCSR[10] = RT_LE2H_U16(initblk.ladrf3); \
1484 pData->aCSR[11] = RT_LE2H_U16(initblk.ladrf4); \
1485 pData->aCSR[12] = RT_LE2H_U16(initblk.padr1); \
1486 pData->aCSR[13] = RT_LE2H_U16(initblk.padr2); \
1487 pData->aCSR[14] = RT_LE2H_U16(initblk.padr3); \
1488 pData->GCRDRA = PHYSADDR(pData, initblk.rdra); \
1489 pData->GCTDRA = PHYSADDR(pData, initblk.tdra); \
1490} while (0)
1491
1492 pcnetEnablePrivateIf(pData);
1493
1494 if (BCR_SSIZE32(pData))
1495 {
1496 struct INITBLK32 initblk;
1497 pData->GCUpperPhys = 0;
1498 PCNET_INIT();
1499 Log(("#%d initblk.rlen=%#04x, initblk.tlen=%#04x\n",
1500 PCNET_INST_NR, initblk.rlen, initblk.tlen));
1501 }
1502 else
1503 {
1504 struct INITBLK16 initblk;
1505 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
1506 PCNET_INIT();
1507 Log(("#%d initblk.rlen=%#04x, initblk.tlen=%#04x\n",
1508 PCNET_INST_NR, initblk.rlen, initblk.tlen));
1509 }
1510
1511#undef PCNET_INIT
1512
1513 if (pData->pDrv)
1514 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
1515
1516 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1517 CSR_XMTRC(pData) = CSR_XMTRL(pData);
1518
1519#ifdef PCNET_NO_POLLING
1520 pcnetUpdateRingHandlers(pData);
1521#endif
1522
1523 /* Reset cached RX and TX states */
1524 CSR_CRST(pData) = CSR_CRBC(pData) = CSR_NRST(pData) = CSR_NRBC(pData) = 0;
1525 CSR_CXST(pData) = CSR_CXBC(pData) = CSR_NXST(pData) = CSR_NXBC(pData) = 0;
1526
1527 LogRel(("PCNet#%d: Init: ss32=%d GCRDRA=%#010x[%d] GCTDRA=%#010x[%d]\n",
1528 PCNET_INST_NR, BCR_SSIZE32(pData),
1529 pData->GCRDRA, CSR_RCVRL(pData), pData->GCTDRA, CSR_XMTRL(pData)));
1530
1531 pData->aCSR[0] |= 0x0101; /* Initialization done */
1532 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1533}
1534#endif /* IN_RING3 */
1535
1536/**
1537 * Start RX/TX operation.
1538 */
1539static void pcnetStart(PCNetState *pData)
1540{
1541 Log(("#%d pcnetStart:\n", PCNET_INST_NR));
1542 if (!CSR_DTX(pData))
1543 pData->aCSR[0] |= 0x0010; /* set TXON */
1544 if (!CSR_DRX(pData))
1545 pData->aCSR[0] |= 0x0020; /* set RXON */
1546 pcnetEnablePrivateIf(pData);
1547 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1548 pData->aCSR[0] |= 0x0002; /* STRT */
1549}
1550
1551/**
1552 * Stop RX/TX operation.
1553 */
1554static void pcnetStop(PCNetState *pData)
1555{
1556 Log(("#%d pcnetStop:\n", PCNET_INST_NR));
1557 pData->aCSR[0] &= ~0x7feb;
1558 pData->aCSR[0] |= 0x0014;
1559 pData->aCSR[4] &= ~0x02c2;
1560 pData->aCSR[5] &= ~0x0011;
1561 pcnetEnablePrivateIf(pData);
1562 pcnetPollTimer(pData);
1563}
1564
1565#ifdef IN_RING3
1566static DECLCALLBACK(bool) pcnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1567{
1568 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1569 if (pData->pDrv)
1570 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1571 return true;
1572}
1573#endif
1574
1575
1576/**
1577 * Poll Receive Descriptor Table Entry and cache the results in the appropriate registers.
1578 * Note: Once a descriptor belongs to the network card (this driver), it cannot be changed
1579 * by the host (the guest driver) anymore. Well, it could but the results are undefined by
1580 * definition.
1581 * @param fSkipCurrent if true, don't scan the current RDTE.
1582 */
1583static void pcnetRdtePoll(PCNetState *pData, bool fSkipCurrent=false)
1584{
1585 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatRdtePoll), a);
1586 /* assume lack of a next receive descriptor */
1587 CSR_NRST(pData) = 0;
1588
1589 if (RT_LIKELY(pData->GCRDRA))
1590 {
1591 /*
1592 * The current receive message descriptor.
1593 */
1594 RMD rmd;
1595 int i = CSR_RCVRC(pData);
1596 RTGCPHYS32 addr;
1597
1598 if (i < 1)
1599 i = CSR_RCVRL(pData);
1600
1601 if (!fSkipCurrent)
1602 {
1603 addr = pcnetRdraAddr(pData, i);
1604 CSR_CRDA(pData) = CSR_CRBA(pData) = 0;
1605 CSR_CRBC(pData) = CSR_CRST(pData) = 0;
1606 if (!pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr), true))
1607 {
1608 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1609 return;
1610 }
1611 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1612 {
1613 CSR_CRDA(pData) = addr; /* Receive Descriptor Address */
1614 CSR_CRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1615 CSR_CRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1616 CSR_CRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1617#ifdef IN_RING3
1618 if (pData->pDrv)
1619 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1620#else
1621 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pCanRxQueue));
1622 if (pItem)
1623 PDMQueueInsert(CTXSUFF(pData->pCanRxQueue), pItem);
1624#endif
1625 }
1626 else
1627 {
1628 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1629 /* This is not problematic since we don't own the descriptor */
1630 LogRel(("PCNet#%d: BAD RMD ENTRIES AT %#010x (i=%d)\n",
1631 PCNET_INST_NR, addr, i));
1632 return;
1633 }
1634 }
1635
1636 /*
1637 * The next descriptor.
1638 */
1639 if (--i < 1)
1640 i = CSR_RCVRL(pData);
1641 addr = pcnetRdraAddr(pData, i);
1642 CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1643 CSR_NRBC(pData) = 0;
1644 if (!pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr), true))
1645 {
1646 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1647 return;
1648 }
1649 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1650 {
1651 CSR_NRDA(pData) = addr; /* Receive Descriptor Address */
1652 CSR_NRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1653 CSR_NRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1654 CSR_NRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1655 }
1656 else
1657 {
1658 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1659 /* This is not problematic since we don't own the descriptor */
1660 LogRel(("PCNet#%d: BAD RMD ENTRIES + AT %#010x (i=%d)\n",
1661 PCNET_INST_NR, addr, i));
1662 return;
1663 }
1664
1665 /**
1666 * @todo NNRD
1667 */
1668 }
1669 else
1670 {
1671 CSR_CRDA(pData) = CSR_CRBA(pData) = CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1672 CSR_CRBC(pData) = CSR_NRBC(pData) = CSR_CRST(pData) = 0;
1673 }
1674 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1675}
1676
1677/**
1678 * Poll Transmit Descriptor Table Entry
1679 * @return true if transmit descriptors available
1680 */
1681static int pcnetTdtePoll(PCNetState *pData, TMD *tmd)
1682{
1683 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTdtePoll), a);
1684 if (RT_LIKELY(pData->GCTDRA))
1685 {
1686 RTGCPHYS32 cxda = pcnetTdraAddr(pData, CSR_XMTRC(pData));
1687
1688 if (!pcnetTmdLoad(pData, tmd, PHYSADDR(pData, cxda), true))
1689 {
1690 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1691 return 0;
1692 }
1693
1694 if (RT_UNLIKELY(tmd->tmd1.ones != 15))
1695 {
1696 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1697 LogRel(("PCNet#%d: BAD TMD XDA=%#010x\n",
1698 PCNET_INST_NR, PHYSADDR(pData, cxda)));
1699 return 0;
1700 }
1701
1702 /* previous xmit descriptor */
1703 CSR_PXDA(pData) = CSR_CXDA(pData);
1704 CSR_PXBC(pData) = CSR_CXBC(pData);
1705 CSR_PXST(pData) = CSR_CXST(pData);
1706
1707 /* set current trasmit decriptor. */
1708 CSR_CXDA(pData) = cxda;
1709 CSR_CXBC(pData) = tmd->tmd1.bcnt;
1710 CSR_CXST(pData) = ((uint32_t *)tmd)[1] >> 16;
1711 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1712 return CARD_IS_OWNER(CSR_CXST(pData));
1713 }
1714 else
1715 {
1716 /** @todo consistency with previous receive descriptor */
1717 CSR_CXDA(pData) = 0;
1718 CSR_CXBC(pData) = CSR_CXST(pData) = 0;
1719 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1720 return 0;
1721 }
1722}
1723
1724
1725#ifdef IN_RING3
1726
1727/**
1728 * Write data into guest receive buffers.
1729 */
1730static void pcnetReceiveNoSync(PCNetState *pData, const uint8_t *buf, int size)
1731{
1732 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1733 int is_padr = 0, is_bcast = 0, is_ladr = 0;
1734 unsigned i;
1735 int pkt_size;
1736
1737 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData) || !size))
1738 return;
1739
1740 /*
1741 * Drop packets if the VM is not running yet/anymore.
1742 */
1743 if (PDMDevHlpVMState(pDevIns) != VMSTATE_RUNNING)
1744 return;
1745
1746 Log(("#%d pcnetReceiveNoSync: size=%d\n", PCNET_INST_NR, size));
1747
1748 /*
1749 * Perform address matching.
1750 */
1751 if ( CSR_PROM(pData)
1752 || (is_padr = padr_match(pData, buf, size))
1753 || (is_bcast = padr_bcast(pData, buf, size))
1754 || (is_ladr = ladr_match(pData, buf, size)))
1755 {
1756 if (HOST_IS_OWNER(CSR_CRST(pData)))
1757 pcnetRdtePoll(pData);
1758 if (RT_UNLIKELY(HOST_IS_OWNER(CSR_CRST(pData))))
1759 {
1760 /* Not owned by controller. This should not be possible as
1761 * we already called pcnetCanReceive(). */
1762 LogRel(("PCNet#%d: no buffer: RCVRC=%d\n",
1763 PCNET_INST_NR, CSR_RCVRC(pData)));
1764 /* Dump the status of all RX descriptors */
1765 const unsigned cb = 1 << pData->iLog2DescSize;
1766 RTGCPHYS32 GCPhys = pData->GCRDRA;
1767 i = CSR_RCVRL(pData);
1768 while (i-- > 0)
1769 {
1770 RMD rmd;
1771 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys), false);
1772 LogRel((" %#010x\n", rmd.rmd1));
1773 GCPhys += cb;
1774 }
1775 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1776 CSR_MISSC(pData)++;
1777 }
1778 else
1779 {
1780 uint8_t *src = &pData->abRecvBuf[8];
1781 RTGCPHYS32 crda = CSR_CRDA(pData);
1782 RTGCPHYS32 next_crda;
1783 RMD rmd, next_rmd;
1784 int pktcount = 0;
1785
1786 memcpy(src, buf, size);
1787 if (!CSR_ASTRP_RCV(pData))
1788 {
1789 uint32_t fcs = ~0;
1790 uint8_t *p = src;
1791
1792 while (size < 60)
1793 src[size++] = 0;
1794 while (p != &src[size])
1795 CRC(fcs, *p++);
1796 ((uint32_t *)&src[size])[0] = htonl(fcs);
1797 /* FCS at end of packet */
1798 }
1799 size += 4;
1800 pkt_size = size;
1801
1802#ifdef PCNET_DEBUG_MATCH
1803 PRINT_PKTHDR(buf);
1804#endif
1805
1806 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, crda), false);
1807 /*if (!CSR_LAPPEN(pData))*/
1808 rmd.rmd1.stp = 1;
1809
1810 int count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1811 RTGCPHYS32 rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1812#if 0
1813 if (pData->fPrivIfEnabled)
1814 {
1815 uint8_t *pb = (uint8_t*)pData->CTXSUFF(pSharedMMIO)
1816 + rbadr - pData->GCRDRA + pData->CTXSUFF(pSharedMMIO)->V.V1.offRxDescriptors;
1817 memcpy(pb, src, count);
1818 }
1819 else
1820#endif
1821 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1822 src += count;
1823 size -= count;
1824 pktcount++;
1825
1826 /* Read current receive descriptor index */
1827 i = CSR_RCVRC(pData);
1828
1829 while (size > 0)
1830 {
1831 /* Read the entire next descriptor as we're likely to need it. */
1832 if (--i < 1)
1833 i = CSR_RCVRL(pData);
1834 next_crda = pcnetRdraAddr(pData, i);
1835
1836 /* Check next descriptor's own bit. If we don't own it, we have
1837 * to quit and write error status into the last descriptor we own.
1838 */
1839 if (!pcnetRmdLoad(pData, &next_rmd, PHYSADDR(pData, next_crda), true))
1840 break;
1841
1842 /* Write back current descriptor, clear the own bit. */
1843 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1844
1845 /* Switch to the next descriptor */
1846 crda = next_crda;
1847 rmd = next_rmd;
1848
1849 count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1850 RTGCPHYS32 rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1851#if 0
1852 if (pData->fPrivIfEnabled)
1853 {
1854 uint8_t *pb = (uint8_t*)pData->CTXSUFF(pSharedMMIO)
1855 + rbadr - pData->GCRDRA + pData->CTXSUFF(pSharedMMIO)->V.V1.offRxDescriptors;
1856 memcpy(pb, src, count);
1857 }
1858 else
1859#endif
1860 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1861 src += count;
1862 size -= count;
1863 pktcount++;
1864 }
1865
1866 if (RT_LIKELY(size == 0))
1867 {
1868 rmd.rmd1.enp = 1;
1869 rmd.rmd1.pam = !CSR_PROM(pData) && is_padr;
1870 rmd.rmd1.lafm = !CSR_PROM(pData) && is_ladr;
1871 rmd.rmd1.bam = !CSR_PROM(pData) && is_bcast;
1872 rmd.rmd2.mcnt = pkt_size;
1873
1874 STAM_REL_COUNTER_ADD(&pData->StatReceiveBytes, pkt_size);
1875 }
1876 else
1877 {
1878 LogRel(("PCNet#%d: Overflow by %ubytes\n",
1879 PCNET_INST_NR, size));
1880 rmd.rmd1.oflo = 1;
1881 rmd.rmd1.buff = 1;
1882 rmd.rmd1.err = 1;
1883 }
1884
1885 /* write back, clear the own bit */
1886 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1887
1888 pData->aCSR[0] |= 0x0400;
1889
1890 Log(("#%d RCVRC=%d CRDA=%#010x BLKS=%d\n", PCNET_INST_NR,
1891 CSR_RCVRC(pData), PHYSADDR(pData, CSR_CRDA(pData)), pktcount));
1892#ifdef PCNET_DEBUG_RMD
1893 PRINT_RMD(&rmd);
1894#endif
1895
1896 while (pktcount--)
1897 {
1898 if (CSR_RCVRC(pData) < 2)
1899 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1900 else
1901 CSR_RCVRC(pData)--;
1902 }
1903 /* guest driver is owner: force repoll of current and next RDTEs */
1904 CSR_CRST(pData) = 0;
1905 }
1906 }
1907
1908 /* see description of TXDPOLL:
1909 * ``transmit polling will take place following receive activities'' */
1910 pcnetPollRxTx(pData);
1911 pcnetUpdateIrq(pData);
1912}
1913
1914
1915/**
1916 * Checks if the link is up.
1917 * @returns true if the link is up.
1918 * @returns false if the link is down.
1919 */
1920DECLINLINE(bool) pcnetIsLinkUp(PCNetState *pData)
1921{
1922 return pData->pDrv && !pData->fLinkTempDown && pData->fLinkUp;
1923}
1924
1925
1926/**
1927 * Transmit queue consumer
1928 * This is just a very simple way of delaying sending to R3.
1929 *
1930 * @returns Success indicator.
1931 * If false the item will not be removed and the flushing will stop.
1932 * @param pDevIns The device instance.
1933 * @param pItem The item to consume. Upon return this item will be freed.
1934 */
1935static DECLCALLBACK(bool) pcnetXmitQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1936{
1937 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1938 NOREF(pItem);
1939
1940 /* Clear counter .*/
1941 ASMAtomicAndU32(&pData->cPendingSends, 0);
1942#ifdef PCNET_QUEUE_SEND_PACKETS
1943 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1944 AssertReleaseRC(rc);
1945 pcnetSyncTransmit(pData);
1946 PDMCritSectLeave(&pData->CritSect);
1947#else
1948 int rc = RTSemEventSignal(pData->hSendEventSem);
1949 AssertRC(rc);
1950#endif
1951 return true;
1952}
1953
1954
1955/**
1956 * Scraps the top frame.
1957 * This is done as a precaution against mess left over by on
1958 */
1959DECLINLINE(void) pcnetXmitScrapFrame(PCNetState *pData)
1960{
1961 pData->pvSendFrame = NULL;
1962 pData->cbSendFrame = 0;
1963}
1964
1965
1966/**
1967 * Reads the first part of a frame
1968 */
1969DECLINLINE(void) pcnetXmitRead1st(PCNetState *pData, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
1970{
1971 Assert(PDMCritSectIsOwner(&pData->CritSect));
1972 Assert(cbFrame < sizeof(pData->abSendBuf));
1973
1974#ifdef PCNET_QUEUE_SEND_PACKETS
1975 AssertRelease(pData->cXmitRingBufPending < PCNET_MAX_XMIT_SLOTS-1);
1976 pData->pvSendFrame = pData->apXmitRingBuffer[pData->iXmitRingBufProd];
1977#else
1978 pData->pvSendFrame = pData->abSendBuf;
1979#endif
1980 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame, pData->pvSendFrame, cbFrame);
1981 pData->cbSendFrame = cbFrame;
1982}
1983
1984
1985/**
1986 * Reads more into the current frame.
1987 */
1988DECLINLINE(void) pcnetXmitReadMore(PCNetState *pData, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
1989{
1990 Assert(pData->cbSendFrame + cbFrame <= MAX_FRAME);
1991 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame, pData->pvSendFrame + pData->cbSendFrame, cbFrame);
1992 pData->cbSendFrame += cbFrame;
1993}
1994
1995
1996/**
1997 * Completes the current frame.
1998 * If we've reached the maxium number of frames, they will be flushed.
1999 */
2000DECLINLINE(int) pcnetXmitCompleteFrame(PCNetState *pData)
2001{
2002#ifdef PCNET_QUEUE_SEND_PACKETS
2003 Assert(PDMCritSectIsOwner(&pData->CritSect));
2004 AssertRelease(pData->cXmitRingBufPending < PCNET_MAX_XMIT_SLOTS-1);
2005 Assert(!pData->cbXmitRingBuffer[pData->iXmitRingBufProd]);
2006
2007 pData->cbXmitRingBuffer[pData->iXmitRingBufProd] = (uint16_t)pData->cbSendFrame;
2008 pData->iXmitRingBufProd = (pData->iXmitRingBufProd+1) & PCNET_MAX_XMIT_SLOTS_MASK;
2009 ASMAtomicIncS32(&pData->cXmitRingBufPending);
2010
2011 int rc = RTSemEventSignal(pData->hSendEventSem);
2012 AssertRC(rc);
2013
2014 return VINF_SUCCESS;
2015#else
2016 /* Don't hold the critical section while transmitting data. */
2017 /** @note also avoids deadlocks with NAT as it can call us right back. */
2018 PDMCritSectLeave(&pData->CritSect);
2019
2020 STAM_PROFILE_ADV_START(&pData->StatTransmitSend, a);
2021 if (pData->cbSendFrame > 70) /* unqualified guess */
2022 pData->Led.Asserted.s.fWriting = pData->Led.Actual.s.fWriting = 1;
2023
2024 pData->pDrv->pfnSend(pData->pDrv, pData->pvSendFrame, pData->cbSendFrame);
2025 STAM_REL_COUNTER_ADD(&pData->StatTransmitBytes, pData->cbSendFrame);
2026 pData->Led.Actual.s.fWriting = 0;
2027 STAM_PROFILE_ADV_STOP(&pData->StatTransmitSend, a);
2028
2029 return PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
2030#endif
2031}
2032
2033
2034/**
2035 * Fails a TMD with a link down error.
2036 */
2037static void pcnetXmitFailTMDLinkDown(PCNetState *pData, TMD *pTmd)
2038{
2039 /* make carrier error - hope this is correct. */
2040 pData->cLinkDownReported++;
2041 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
2042 pData->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR */
2043 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
2044 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
2045 PCNET_INST_NR, pData->aBCR[BCR_SWS]));
2046}
2047
2048/**
2049 * Fails a TMD with a generic error.
2050 */
2051static void pcnetXmitFailTMDGeneric(PCNetState *pData, TMD *pTmd)
2052{
2053 /* make carrier error - hope this is correct. */
2054 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
2055 pData->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR */
2056 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
2057 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
2058 PCNET_INST_NR, pData->aBCR[BCR_SWS]));
2059}
2060
2061
2062/**
2063 * Transmit a loopback frame.
2064 */
2065DECLINLINE(void) pcnetXmitLoopbackFrame(PCNetState *pData)
2066{
2067 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
2068 if (HOST_IS_OWNER(CSR_CRST(pData)))
2069 pcnetRdtePoll(pData);
2070
2071 Assert(pData->pvSendFrame);
2072 pcnetReceiveNoSync(pData, (const uint8_t *)pData->pvSendFrame, pData->cbSendFrame);
2073 pcnetXmitScrapFrame(pData);
2074 pData->Led.Actual.s.fReading = 0;
2075}
2076
2077/**
2078 * Flushes queued frames.
2079 */
2080DECLINLINE(void) pcnetXmitFlushFrames(PCNetState *pData)
2081{
2082 pcnetXmitQueueConsumer(CTXSUFF(pData->pDevIns), NULL);
2083}
2084
2085#endif /* IN_RING3 */
2086
2087
2088
2089/**
2090 * Try to transmit frames
2091 */
2092static void pcnetTransmit(PCNetState *pData)
2093{
2094 if (RT_UNLIKELY(!CSR_TXON(pData)))
2095 {
2096 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
2097 return;
2098 }
2099
2100 /*
2101 * Check the current transmit descriptors.
2102 */
2103 TMD tmd;
2104 if (!pcnetTdtePoll(pData, &tmd))
2105 return;
2106
2107 /*
2108 * Clear TDMD.
2109 */
2110 pData->aCSR[0] &= ~0x0008;
2111
2112 /*
2113 * If we're in Ring-3 we should flush the queue now, in GC/R0 we'll queue a flush job.
2114 */
2115#ifdef IN_RING3
2116 pcnetXmitFlushFrames(pData);
2117#else
2118# if 1
2119 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
2120 if (RT_UNLIKELY(pItem))
2121 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
2122# else
2123 if (ASMAtomicIncU32(&pData->cPendingSends) < 16)
2124 {
2125 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
2126 if (RT_UNLIKELY(pItem))
2127 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
2128 }
2129 else
2130 PDMQueueFlush(CTXSUFF(pData->pXmitQueue));
2131# endif
2132#endif
2133}
2134
2135#ifdef IN_RING3
2136
2137/**
2138 * Try to transmit frames
2139 */
2140#ifdef PCNET_QUEUE_SEND_PACKETS
2141static int pcnetAsyncTransmit(PCNetState *pData)
2142{
2143 Assert(PDMCritSectIsOwner(&pData->CritSect));
2144 size_t cb;
2145
2146 while ((pData->cXmitRingBufPending > 0))
2147 {
2148 cb = pData->cbXmitRingBuffer[pData->iXmitRingBufCons];
2149
2150 /* Don't hold the critical section while transmitting data. */
2151 /** @note also avoids deadlocks with NAT as it can call us right back. */
2152 PDMCritSectLeave(&pData->CritSect);
2153
2154 STAM_PROFILE_ADV_START(&pData->StatTransmitSend, a);
2155 if (cb > 70) /* unqualified guess */
2156 pData->Led.Asserted.s.fWriting = pData->Led.Actual.s.fWriting = 1;
2157
2158 pData->pDrv->pfnSend(pData->pDrv, pData->apXmitRingBuffer[pData->iXmitRingBufCons], cb);
2159 STAM_REL_COUNTER_ADD(&pData->StatTransmitBytes, cb);
2160 pData->Led.Actual.s.fWriting = 0;
2161 STAM_PROFILE_ADV_STOP(&pData->StatTransmitSend, a);
2162
2163 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
2164 AssertReleaseRC(rc);
2165
2166 pData->cbXmitRingBuffer[pData->iXmitRingBufCons] = 0;
2167 pData->iXmitRingBufCons = (pData->iXmitRingBufCons+1) & PCNET_MAX_XMIT_SLOTS_MASK;
2168 ASMAtomicDecS32(&pData->cXmitRingBufPending);
2169 }
2170 return VINF_SUCCESS;
2171}
2172
2173static int pcnetSyncTransmit(PCNetState *pData)
2174#else
2175static int pcnetAsyncTransmit(PCNetState *pData)
2176#endif
2177{
2178 unsigned cFlushIrq = 0;
2179
2180 Assert(PDMCritSectIsOwner(&pData->CritSect));
2181
2182 if (RT_UNLIKELY(!CSR_TXON(pData)))
2183 {
2184 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
2185 return VINF_SUCCESS;
2186 }
2187
2188 /*
2189 * Iterate the transmit descriptors.
2190 */
2191 STAM_PROFILE_ADV_START(&pData->StatTransmit, a);
2192 do
2193 {
2194#ifdef VBOX_WITH_STATISTICS
2195 unsigned cBuffers = 1;
2196#endif
2197 TMD tmd;
2198 if (!pcnetTdtePoll(pData, &tmd))
2199 break;
2200
2201 /* Don't continue sending packets when the link is down. */
2202 if (RT_UNLIKELY( !pcnetIsLinkUp(pData)
2203 && pData->cLinkDownReported > PCNET_MAX_LINKDOWN_REPORTED)
2204 )
2205 break;
2206
2207#ifdef PCNET_DEBUG_TMD
2208 Log2(("#%d TMDLOAD %#010x\n", PCNET_INST_NR, PHYSADDR(pData, CSR_CXDA(pData))));
2209 PRINT_TMD(&tmd);
2210#endif
2211 pcnetXmitScrapFrame(pData);
2212
2213 /*
2214 * The typical case - a complete packet.
2215 */
2216 if (tmd.tmd1.stp && tmd.tmd1.enp)
2217 {
2218 const unsigned cb = 4096 - tmd.tmd1.bcnt;
2219 Log(("#%d pcnetTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNET_INST_NR, cb, CSR_XMTRC(pData)));
2220
2221 if (RT_LIKELY(pcnetIsLinkUp(pData) || CSR_LOOP(pData)))
2222 {
2223 /* From the manual: ``A zero length buffer is acceptable as
2224 * long as it is not the last buffer in a chain (STP = 0 and
2225 * ENP = 1).'' That means that the first buffer might have a
2226 * zero length if it is not the last one in the chain. */
2227 if (RT_LIKELY(cb <= MAX_FRAME))
2228 {
2229 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2230 if (CSR_LOOP(pData))
2231 pcnetXmitLoopbackFrame(pData);
2232 else
2233 {
2234 int rc = pcnetXmitCompleteFrame(pData);
2235 AssertRCReturn(rc, rc);
2236 }
2237 }
2238 else if (cb == 4096)
2239 {
2240 /* The Windows NT4 pcnet driver sometimes marks the first
2241 * unused descriptor as owned by us. Ignore that (by
2242 * passing it back). Do not update the ring counter in this
2243 * case (otherwise that driver becomes even more confused,
2244 * which causes transmit to stall for about 10 seconds).
2245 * This is just a workaround, not a final solution. */
2246 /* r=frank: IMHO this is the correct implementation. The
2247 * manual says: ``If the OWN bit is set and the buffer
2248 * length is 0, the OWN bit will be cleared. In the C-LANCE
2249 * the buffer length of 0 is interpreted as a 4096-byte
2250 * buffer.'' */
2251 LogRel(("PCNet#%d: pcnetAsyncTransmit: illegal 4kb frame -> ignoring\n", PCNET_INST_NR));
2252 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2253 break;
2254 }
2255 else
2256 {
2257 /* Signal error, as this violates the Ethernet specs. */
2258 /** @todo check if the correct error is generated. */
2259 LogRel(("PCNet#%d: pcnetAsyncTransmit: illegal 4kb frame -> signalling error\n", PCNET_INST_NR));
2260
2261 pcnetXmitFailTMDGeneric(pData, &tmd);
2262 }
2263 }
2264 else
2265 pcnetXmitFailTMDLinkDown(pData, &tmd);
2266
2267 /* Write back the TMD and pass it to the host (clear own bit). */
2268 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2269
2270 /* advance the ring counter register */
2271 if (CSR_XMTRC(pData) < 2)
2272 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2273 else
2274 CSR_XMTRC(pData)--;
2275 }
2276 else if (tmd.tmd1.stp)
2277 {
2278 /*
2279 * Read TMDs until end-of-packet or tdte poll fails (underflow).
2280 */
2281 bool fDropFrame = false;
2282 unsigned cb = 4096 - tmd.tmd1.bcnt;
2283 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2284 for (;;)
2285 {
2286 /*
2287 * Advance the ring counter register and check the next tmd.
2288 */
2289#ifdef LOG_ENABLED
2290 const uint32_t iStart = CSR_XMTRC(pData);
2291#endif
2292 const uint32_t GCPhysPrevTmd = PHYSADDR(pData, CSR_CXDA(pData));
2293 if (CSR_XMTRC(pData) < 2)
2294 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2295 else
2296 CSR_XMTRC(pData)--;
2297
2298 TMD dummy;
2299 if (!pcnetTdtePoll(pData, &dummy))
2300 {
2301 /*
2302 * Underflow!
2303 */
2304 tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
2305 pData->aCSR[0] |= 0x0200; /* set TINT */
2306 if (!CSR_DXSUFLO(pData)) /* stop on xmit underflow */
2307 pData->aCSR[0] &= ~0x0010; /* clear TXON */
2308 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2309 AssertMsgFailed(("pcnetTransmit: Underflow!!!\n"));
2310 break;
2311 }
2312
2313 /* release & save the previous tmd, pass it to the host */
2314 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2315
2316 /*
2317 * The next tdm.
2318 */
2319#ifdef VBOX_WITH_STATISTICS
2320 cBuffers++;
2321#endif
2322 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)), false);
2323 cb = 4096 - tmd.tmd1.bcnt;
2324 if ( pData->cbSendFrame + cb < MAX_FRAME
2325 && !fDropFrame)
2326 pcnetXmitReadMore(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2327 else
2328 {
2329 AssertMsg(fDropFrame, ("pcnetTransmit: Frame is too big!!! %d bytes\n",
2330 pData->cbSendFrame + cb));
2331 fDropFrame = true;
2332 }
2333 if (tmd.tmd1.enp)
2334 {
2335 Log(("#%d pcnetTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNET_INST_NR,
2336 pData->cbSendFrame, iStart, CSR_XMTRC(pData)));
2337 if (pcnetIsLinkUp(pData) && !fDropFrame)
2338 {
2339 int rc = pcnetXmitCompleteFrame(pData);
2340 AssertRCReturn(rc, rc);
2341 }
2342 else if (CSR_LOOP(pData) && !fDropFrame)
2343 pcnetXmitLoopbackFrame(pData);
2344 else
2345 {
2346 if (!fDropFrame)
2347 pcnetXmitFailTMDLinkDown(pData, &tmd);
2348 pcnetXmitScrapFrame(pData);
2349 }
2350
2351 /* Write back the TMD, pass it to the host */
2352 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2353
2354 /* advance the ring counter register */
2355 if (CSR_XMTRC(pData) < 2)
2356 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2357 else
2358 CSR_XMTRC(pData)--;
2359 break;
2360 }
2361 }
2362 }
2363 else
2364 {
2365 /*
2366 * We underflowed in a previous transfer, or the driver is giving us shit.
2367 * Simply stop the transmitting for now.
2368 */
2369 /** @todo according to the specs we're supposed to clear the own bit and move on to the next one. */
2370 Log(("#%d pcnetTransmit: guest is giving us shit!\n", PCNET_INST_NR));
2371 break;
2372 }
2373 /* Update TDMD, TXSTRT and TINT. */
2374 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
2375
2376 pData->aCSR[4] |= 0x0008; /* set TXSTRT */
2377 if ( !CSR_TOKINTD(pData) /* Transmit OK Interrupt Disable, no infl. on errors. */
2378 || (CSR_LTINTEN(pData) && tmd.tmd1.ltint)
2379 || tmd.tmd1.err)
2380 {
2381 cFlushIrq++;
2382 }
2383
2384 /** @todo should we continue after an error (tmd.tmd1.err) or not? */
2385
2386 STAM_COUNTER_INC(&pData->aStatXmitChainCounts[RT_MIN(cBuffers,
2387 ELEMENTS(pData->aStatXmitChainCounts)) - 1]);
2388 } while (CSR_TXON(pData)); /* transfer on */
2389
2390 if (cFlushIrq)
2391 {
2392 STAM_COUNTER_INC(&pData->aStatXmitFlush[RT_MIN(cFlushIrq, ELEMENTS(pData->aStatXmitFlush)) - 1]);
2393 pData->aCSR[0] |= 0x0200; /* set TINT */
2394 pcnetUpdateIrq(pData);
2395 }
2396
2397 STAM_PROFILE_ADV_STOP(&pData->StatTransmit, a);
2398
2399 return VINF_SUCCESS;
2400}
2401
2402
2403/**
2404 * Async I/O thread for delayed sending of packets.
2405 *
2406 * @returns VBox status code. Returning failure will naturally terminate the thread.
2407 * @param pDevIns The pcnet device instance.
2408 * @param pThread The thread.
2409 */
2410static DECLCALLBACK(int) pcnetAsyncSendThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
2411{
2412 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
2413
2414 /*
2415 * We can enter this function in two states, initializing or resuming.
2416 *
2417 * The idea about the initializing bit is that we can do per-thread
2418 * initialization while the creator thread can still pick up errors.
2419 * At present, there is nothing to init, or at least nothing that
2420 * need initing in the thread.
2421 */
2422 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
2423 return VINF_SUCCESS;
2424
2425 /*
2426 * Stay in the run-loop until we're supposed to leave the
2427 * running state. If something really bad happens, we'll
2428 * quit the loop while in the running state and return
2429 * an error status to PDM and let it terminate the thread.
2430 */
2431 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
2432 {
2433 /*
2434 * Block until we've got something to send or is supposed
2435 * to leave the running state.
2436 */
2437 int rc = RTSemEventWait(pData->hSendEventSem, RT_INDEFINITE_WAIT);
2438 AssertRCReturn(rc, rc);
2439 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
2440 break;
2441
2442 /*
2443 * Perform async send. Mind that we might be requested to
2444 * suspended while waiting for the critical section.
2445 */
2446 rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
2447 AssertReleaseRCReturn(rc, rc);
2448
2449 if (pThread->enmState == PDMTHREADSTATE_RUNNING)
2450 {
2451 rc = pcnetAsyncTransmit(pData);
2452 AssertReleaseRC(rc);
2453 }
2454
2455 PDMCritSectLeave(&pData->CritSect);
2456 }
2457
2458 /* The thread is being suspended or terminated. */
2459 return VINF_SUCCESS;
2460}
2461
2462
2463/**
2464 * Unblock the send thread so it can respond to a state change.
2465 *
2466 * @returns VBox status code.
2467 * @param pDevIns The pcnet device instance.
2468 * @param pThread The send thread.
2469 */
2470static DECLCALLBACK(int) pcnetAsyncSendThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
2471{
2472 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
2473 return RTSemEventSignal(pData->hSendEventSem);
2474}
2475
2476#endif /* IN_RING3 */
2477
2478/**
2479 * Poll for changes in RX and TX descriptor rings.
2480 */
2481static void pcnetPollRxTx(PCNetState *pData)
2482{
2483 if (CSR_RXON(pData))
2484 if (HOST_IS_OWNER(CSR_CRST(pData))) /* Only poll RDTEs if none available */
2485 pcnetRdtePoll(pData);
2486
2487 if (CSR_TDMD(pData) || (CSR_TXON(pData) && !CSR_DPOLL(pData)))
2488 pcnetTransmit(pData);
2489}
2490
2491
2492/**
2493 * Update the poller timer
2494 * @thread EMT,
2495 */
2496static void pcnetPollTimer(PCNetState *pData)
2497{
2498 STAM_PROFILE_ADV_START(&pData->StatPollTimer, a);
2499
2500#ifdef LOG_ENABLED
2501 TMD dummy;
2502 if (CSR_STOP(pData) || CSR_SPND(pData))
2503 Log2(("#%d pcnetPollTimer time=%#010llx CSR_STOP=%d CSR_SPND=%d\n",
2504 PCNET_INST_NR, RTTimeMilliTS(), CSR_STOP(pData), CSR_SPND(pData)));
2505 else
2506 Log2(("#%d pcnetPollTimer time=%#010llx TDMD=%d TXON=%d POLL=%d TDTE=%d TDRA=%#x\n",
2507 PCNET_INST_NR, RTTimeMilliTS(), CSR_TDMD(pData), CSR_TXON(pData),
2508 !CSR_DPOLL(pData), pcnetTdtePoll(pData, &dummy), pData->GCTDRA));
2509 Log2(("#%d pcnetPollTimer: CSR_CXDA=%#x CSR_XMTRL=%d CSR_XMTRC=%d\n",
2510 PCNET_INST_NR, CSR_CXDA(pData), CSR_XMTRL(pData), CSR_XMTRC(pData)));
2511#endif
2512#ifdef PCNET_DEBUG_TMD
2513 if (CSR_CXDA(pData))
2514 {
2515 TMD tmd;
2516 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)), false);
2517 Log2(("#%d pcnetPollTimer: TMDLOAD %#010x\n", PCNET_INST_NR, PHYSADDR(pData, CSR_CXDA(pData))));
2518 PRINT_TMD(&tmd);
2519 }
2520#endif
2521 if (CSR_TDMD(pData))
2522 pcnetTransmit(pData);
2523
2524 pcnetUpdateIrq(pData);
2525
2526 if (RT_LIKELY(!CSR_STOP(pData) && !CSR_SPND(pData) && !CSR_DPOLL(pData)))
2527 {
2528 /* We ensure that we poll at least every 2ms (500Hz) but not more often than
2529 * 5000 times per second. This way we completely prevent the overhead from
2530 * heavy reprogramming the timer which turned out to be very CPU-intensive.
2531 * The drawback is that csr46 and csr47 are not updated properly anymore
2532 * but so far I have not seen any guest depending on these values. The 2ms
2533 * interval is the default polling interval of the PCNet card (65536/33MHz). */
2534#ifdef PCNET_NO_POLLING
2535 pcnetPollRxTx(pData);
2536#else
2537 uint64_t u64Now = TMTimerGet(pData->CTXSUFF(pTimerPoll));
2538 if (RT_UNLIKELY(u64Now - pData->u64LastPoll > 200000))
2539 {
2540 pData->u64LastPoll = u64Now;
2541 pcnetPollRxTx(pData);
2542 }
2543 if (!TMTimerIsActive(pData->CTXSUFF(pTimerPoll)))
2544 /* Poll timer interval is fixed to 500Hz. Don't stop it. */
2545 TMTimerSet(pData->CTXSUFF(pTimerPoll),
2546 TMTimerGet(pData->CTXSUFF(pTimerPoll))
2547 + TMTimerFromMilli(pData->CTXSUFF(pTimerPoll), 2));
2548#endif
2549 }
2550 STAM_PROFILE_ADV_STOP(&pData->StatPollTimer, a);
2551}
2552
2553
2554static int pcnetCSRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val)
2555{
2556 int rc = VINF_SUCCESS;
2557#ifdef PCNET_DEBUG_CSR
2558 Log(("#%d pcnetCSRWriteU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
2559#endif
2560 switch (u32RAP)
2561 {
2562 case 0:
2563 {
2564 uint16_t csr0 = pData->aCSR[0];
2565 /* Clear any interrupt flags.
2566 * Don't clear an interrupt flag which was not seen by the guest yet. */
2567 csr0 &= ~(val & 0x7f00 & pData->u16CSR0LastSeenByGuest);
2568 csr0 = (csr0 & ~0x0040) | (val & 0x0048);
2569 val = (val & 0x007f) | (csr0 & 0x7f00);
2570
2571 /* Iff STOP, STRT and INIT are set, clear STRT and INIT */
2572 if ((val & 7) == 7)
2573 val &= ~3;
2574
2575 Log(("#%d CSR0: old=%#06x new=%#06x\n", PCNET_INST_NR, pData->aCSR[0], csr0));
2576
2577#ifndef IN_RING3
2578 if (!(csr0 & 0x0001/*init*/) && (val & 1))
2579 {
2580 Log(("#%d pcnetCSRWriteU16: pcnetInit requested => HC\n", PCNET_INST_NR));
2581 return VINF_IOM_HC_IOPORT_WRITE;
2582 }
2583#endif
2584 pData->aCSR[0] = csr0;
2585
2586 if (!CSR_STOP(pData) && (val & 4))
2587 pcnetStop(pData);
2588
2589#ifdef IN_RING3
2590 if (!CSR_INIT(pData) && (val & 1))
2591 pcnetInit(pData);
2592#endif
2593
2594 if (!CSR_STRT(pData) && (val & 2))
2595 pcnetStart(pData);
2596
2597 if (CSR_TDMD(pData))
2598 pcnetTransmit(pData);
2599
2600 return rc;
2601 }
2602 case 1: /* IADRL */
2603 case 2: /* IADRH */
2604 case 8: /* LADRF 0..15 */
2605 case 9: /* LADRF 16..31 */
2606 case 10: /* LADRF 32..47 */
2607 case 11: /* LADRF 48..63 */
2608 case 12: /* PADR 0..15 */
2609 case 13: /* PADR 16..31 */
2610 case 14: /* PADR 32..47 */
2611 case 18: /* CRBAL */
2612 case 19: /* CRBAU */
2613 case 20: /* CXBAL */
2614 case 21: /* CXBAU */
2615 case 22: /* NRBAL */
2616 case 23: /* NRBAU */
2617 case 26: /* NRDAL */
2618 case 27: /* NRDAU */
2619 case 28: /* CRDAL */
2620 case 29: /* CRDAU */
2621 case 32: /* NXDAL */
2622 case 33: /* NXDAU */
2623 case 34: /* CXDAL */
2624 case 35: /* CXDAU */
2625 case 36: /* NNRDL */
2626 case 37: /* NNRDU */
2627 case 38: /* NNXDL */
2628 case 39: /* NNXDU */
2629 case 40: /* CRBCL */
2630 case 41: /* CRBCU */
2631 case 42: /* CXBCL */
2632 case 43: /* CXBCU */
2633 case 44: /* NRBCL */
2634 case 45: /* NRBCU */
2635 case 46: /* POLL */
2636 case 47: /* POLLINT */
2637 case 72: /* RCVRC */
2638 case 74: /* XMTRC */
2639 case 112: /* MISSC */
2640 if (CSR_STOP(pData) || CSR_SPND(pData))
2641 break;
2642 case 3: /* Interrupt Mask and Deferral Control */
2643 break;
2644 case 4: /* Test and Features Control */
2645 pData->aCSR[4] &= ~(val & 0x026a);
2646 val &= ~0x026a;
2647 val |= pData->aCSR[4] & 0x026a;
2648 break;
2649 case 5: /* Extended Control and Interrupt 1 */
2650 pData->aCSR[5] &= ~(val & 0x0a90);
2651 val &= ~0x0a90;
2652 val |= pData->aCSR[5] & 0x0a90;
2653 break;
2654 case 7: /* Extended Control and Interrupt 2 */
2655 {
2656 uint16_t csr7 = pData->aCSR[7];
2657 csr7 &= ~0x0400 ;
2658 csr7 &= ~(val & 0x0800);
2659 csr7 |= (val & 0x0400);
2660 pData->aCSR[7] = csr7;
2661 return rc;
2662 }
2663 case 15: /* Mode */
2664 if ((pData->aCSR[15] & 0x8000) != (val & 0x8000) && pData->pDrv)
2665 {
2666 Log(("#%d: promiscuous mode changed to %d\n", PCNET_INST_NR, !!(val & 0x8000)));
2667#ifndef IN_RING3
2668 return VINF_IOM_HC_IOPORT_WRITE;
2669#else
2670 /* check for promiscuous mode change */
2671 if (pData->pDrv)
2672 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, !!(val & 0x8000));
2673#endif
2674 }
2675 break;
2676 case 16: /* IADRL */
2677 return pcnetCSRWriteU16(pData, 1, val);
2678 case 17: /* IADRH */
2679 return pcnetCSRWriteU16(pData, 2, val);
2680
2681 /*
2682 * 24 and 25 are the Base Address of Receive Descriptor.
2683 * We combine and mirror these in GCRDRA.
2684 */
2685 case 24: /* BADRL */
2686 case 25: /* BADRU */
2687 if (!CSR_STOP(pData) && !CSR_SPND(pData))
2688 {
2689 Log(("#%d: WRITE CSR%d, %#06x !!\n", PCNET_INST_NR, u32RAP, val));
2690 return rc;
2691 }
2692 if (u32RAP == 24)
2693 pData->GCRDRA = (pData->GCRDRA & 0xffff0000) | (val & 0x0000ffff);
2694 else
2695 pData->GCRDRA = (pData->GCRDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16);
2696 Log(("#%d: WRITE CSR%d, %#06x => GCRDRA=%08x (alt init)\n", PCNET_INST_NR, u32RAP, val, pData->GCRDRA));
2697 break;
2698
2699 /*
2700 * 30 & 31 are the Base Address of Transmit Descriptor.
2701 * We combine and mirrorthese in GCTDRA.
2702 */
2703 case 30: /* BADXL */
2704 case 31: /* BADXU */
2705 if (!CSR_STOP(pData) && !CSR_SPND(pData))
2706 {
2707 Log(("#%d: WRITE CSR%d, %#06x !!\n", PCNET_INST_NR, u32RAP, val));
2708 return rc;
2709 }
2710 if (u32RAP == 30)
2711 pData->GCTDRA = (pData->GCTDRA & 0xffff0000) | (val & 0x0000ffff);
2712 else
2713 pData->GCTDRA = (pData->GCTDRA & 0x0000ffff) | ((val & 0x0000ffff) << 16);
2714 Log(("#%d: WRITE CSR%d, %#06x => GCTDRA=%08x (alt init)\n", PCNET_INST_NR, u32RAP, val, pData->GCTDRA));
2715 break;
2716
2717 case 58: /* Software Style */
2718 rc = pcnetBCRWriteU16(pData, BCR_SWS, val);
2719 break;
2720
2721 /*
2722 * Registers 76 and 78 aren't stored correctly (see todos), but I'm don't dare
2723 * try fix that right now. So, as a quick hack for 'alt init' I'll just correct them here.
2724 */
2725 case 76: /* RCVRL */ /** @todo call pcnetUpdateRingHandlers */
2726 /** @todo receive ring length is stored in two's complement! */
2727 case 78: /* XMTRL */ /** @todo call pcnetUpdateRingHandlers */
2728 /** @todo transmit ring length is stored in two's complement! */
2729 if (!CSR_STOP(pData) && !CSR_SPND(pData))
2730 {
2731 Log(("#%d: WRITE CSR%d, %#06x !!\n", PCNET_INST_NR, u32RAP, val));
2732 return rc;
2733 }
2734 Log(("#%d: WRITE CSR%d, %#06x (hacked %#06x) (alt init)\n", PCNET_INST_NR,
2735 u32RAP, val, 1 + ~(uint16_t)val));
2736 val = 1 + ~(uint16_t)val;
2737
2738 /*
2739 * HACK ALERT! Set the counter registers too.
2740 */
2741 pData->aCSR[u32RAP - 4] = val;
2742 break;
2743
2744 default:
2745 return rc;
2746 }
2747 pData->aCSR[u32RAP] = val;
2748 return rc;
2749}
2750
2751/**
2752 * Encode a 32-bit link speed into a custom 16-bit floating-point value
2753 */
2754static uint32_t pcnetLinkSpd(uint32_t speed)
2755{
2756 unsigned exp = 0;
2757
2758 while (speed & 0xFFFFE000)
2759 {
2760 speed /= 10;
2761 ++exp;
2762 }
2763 return (exp << 13) | speed;
2764}
2765
2766static uint32_t pcnetCSRReadU16(PCNetState *pData, uint32_t u32RAP)
2767{
2768 uint32_t val;
2769 switch (u32RAP)
2770 {
2771 case 0:
2772 pcnetUpdateIrq(pData);
2773 val = pData->aCSR[0];
2774 val |= (val & 0x7800) ? 0x8000 : 0;
2775 pData->u16CSR0LastSeenByGuest = val;
2776 break;
2777 case 16:
2778 return pcnetCSRReadU16(pData, 1);
2779 case 17:
2780 return pcnetCSRReadU16(pData, 2);
2781 case 58:
2782 return pcnetBCRReadU16(pData, BCR_SWS);
2783 case 68: /* Custom register to pass link speed to driver */
2784 return pcnetLinkSpd(pData->u32LinkSpeed);
2785 case 88:
2786 val = pData->aCSR[89];
2787 val <<= 16;
2788 val |= pData->aCSR[88];
2789 break;
2790 default:
2791 val = pData->aCSR[u32RAP];
2792 }
2793#ifdef PCNET_DEBUG_CSR
2794 Log(("#%d pcnetCSRReadU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
2795#endif
2796 return val;
2797}
2798
2799static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val)
2800{
2801 int rc = VINF_SUCCESS;
2802 u32RAP &= 0x7f;
2803#ifdef PCNET_DEBUG_BCR
2804 Log2(("#%d pcnetBCRWriteU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
2805#endif
2806 switch (u32RAP)
2807 {
2808 case BCR_SWS:
2809 if (!(CSR_STOP(pData) || CSR_SPND(pData)))
2810 return rc;
2811 val &= ~0x0300;
2812 switch (val & 0x00ff)
2813 {
2814 default:
2815 Log(("#%d Bad SWSTYLE=%#04x\n", PCNET_INST_NR, val & 0xff));
2816 // fall through
2817 case 0:
2818 val |= 0x0200; /* 16 bit */
2819 pData->iLog2DescSize = 3;
2820 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
2821 break;
2822 case 1:
2823 val |= 0x0100; /* 32 bit */
2824 pData->iLog2DescSize = 4;
2825 pData->GCUpperPhys = 0;
2826 break;
2827 case 2:
2828 case 3:
2829 val |= 0x0300; /* 32 bit */
2830 pData->iLog2DescSize = 4;
2831 pData->GCUpperPhys = 0;
2832 break;
2833 }
2834 Log(("#%d BCR_SWS=%#06x\n", PCNET_INST_NR, val));
2835 pData->aCSR[58] = val;
2836 /* fall through */
2837 case BCR_LNKST:
2838 case BCR_LED1:
2839 case BCR_LED2:
2840 case BCR_LED3:
2841 case BCR_MC:
2842 case BCR_FDC:
2843 case BCR_BSBC:
2844 case BCR_EECAS:
2845 case BCR_PLAT:
2846 case BCR_MIICAS:
2847 case BCR_MIIADDR:
2848 pData->aBCR[u32RAP] = val;
2849 break;
2850
2851 case BCR_STVAL:
2852 val &= 0xffff;
2853 pData->aBCR[BCR_STVAL] = val;
2854 if (pData->fAm79C973)
2855 TMTimerSetNano(pData->CTXSUFF(pTimerSoftInt), 12800U * val);
2856 break;
2857
2858 case BCR_MIIMDR:
2859 pData->aMII[pData->aBCR[BCR_MIIADDR] & 0x1f] = val;
2860#ifdef PCNET_DEBUG_MII
2861 Log(("#%d pcnet: mii write %d <- %#x\n", PCNET_INST_NR, pData->aBCR[BCR_MIIADDR] & 0x1f, val));
2862#endif
2863 break;
2864
2865 default:
2866 break;
2867 }
2868 return rc;
2869}
2870
2871static uint32_t pcnetMIIReadU16(PCNetState *pData, uint32_t miiaddr)
2872{
2873 uint32_t val;
2874 bool autoneg, duplex, fast;
2875 STAM_COUNTER_INC(&pData->StatMIIReads);
2876
2877 autoneg = (pData->aBCR[BCR_MIICAS] & 0x20) != 0;
2878 duplex = (pData->aBCR[BCR_MIICAS] & 0x10) != 0;
2879 fast = (pData->aBCR[BCR_MIICAS] & 0x08) != 0;
2880
2881 switch (miiaddr)
2882 {
2883 case 0:
2884 /* MII basic mode control register. */
2885 val = 0;
2886 if (autoneg)
2887 val |= 0x1000; /* Enable auto negotiation. */
2888 if (fast)
2889 val |= 0x2000; /* 100 Mbps */
2890 if (duplex) /* Full duplex forced */
2891 val |= 0x0100; /* Full duplex */
2892 break;
2893
2894 case 1:
2895 /* MII basic mode status register. */
2896 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2897 | 0x0040 /* Mgmt frame preamble not required. */
2898 | 0x0020 /* Auto-negotiation complete. */
2899 | 0x0008 /* Able to do auto-negotiation. */
2900 | 0x0004 /* Link up. */
2901 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2902 if (!pData->fLinkUp || pData->fLinkTempDown) {
2903 val &= ~(0x0020 | 0x0004);
2904 pData->cLinkDownReported++;
2905 }
2906 if (!autoneg) {
2907 /* Auto-negotiation disabled. */
2908 val &= ~(0x0020 | 0x0008);
2909 if (duplex)
2910 /* Full duplex forced. */
2911 val &= ~0x2800;
2912 else
2913 /* Half duplex forced. */
2914 val &= ~0x5000;
2915
2916 if (fast)
2917 /* 100 Mbps forced */
2918 val &= ~0x1800;
2919 else
2920 /* 10 Mbps forced */
2921 val &= ~0x6000;
2922 }
2923 break;
2924
2925 case 2:
2926 /* PHY identifier 1. */
2927 val = 0x22; /* Am79C874 PHY */
2928 break;
2929
2930 case 3:
2931 /* PHY identifier 2. */
2932 val = 0x561b; /* Am79C874 PHY */
2933 break;
2934
2935 case 4:
2936 /* Advertisement control register. */
2937 val = 0x01e0 /* Try 100mbps FD/HD and 10mbps FD/HD. */
2938#if 0
2939 // Advertising flow control is a) not the default, and b) confuses
2940 // the link speed detection routine in Windows PCnet driver
2941 | 0x0400 /* Try flow control. */
2942#endif
2943 | 0x0001; /* CSMA selector. */
2944 break;
2945
2946 case 5:
2947 /* Link partner ability register. */
2948 if (pData->fLinkUp && !pData->fLinkTempDown)
2949 val = 0x8000 /* Next page bit. */
2950 | 0x4000 /* Link partner acked us. */
2951 | 0x0400 /* Can do flow control. */
2952 | 0x01e0 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2953 | 0x0001; /* Use CSMA selector. */
2954 else
2955 {
2956 val = 0;
2957 pData->cLinkDownReported++;
2958 }
2959 break;
2960
2961 case 6:
2962 /* Auto negotiation expansion register. */
2963 if (pData->fLinkUp && !pData->fLinkTempDown)
2964 val = 0x0008 /* Link partner supports npage. */
2965 | 0x0004 /* Enable npage words. */
2966 | 0x0001; /* Can do N-way auto-negotiation. */
2967 else
2968 {
2969 val = 0;
2970 pData->cLinkDownReported++;
2971 }
2972 break;
2973
2974 default:
2975 val = 0;
2976 break;
2977 }
2978
2979#ifdef PCNET_DEBUG_MII
2980 Log(("#%d pcnet: mii read %d -> %#x\n", PCNET_INST_NR, miiaddr, val));
2981#endif
2982 return val;
2983}
2984
2985static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP)
2986{
2987 uint32_t val;
2988 u32RAP &= 0x7f;
2989 switch (u32RAP)
2990 {
2991 case BCR_LNKST:
2992 case BCR_LED1:
2993 case BCR_LED2:
2994 case BCR_LED3:
2995 val = pData->aBCR[u32RAP] & ~0x8000;
2996 /* Clear LNKSTE if we're not connected or if we've just loaded a VM state. */
2997 if (!pData->pDrv || pData->fLinkTempDown || !pData->fLinkUp)
2998 {
2999 if (u32RAP == 4)
3000 pData->cLinkDownReported++;
3001 val &= ~0x40;
3002 }
3003 val |= (val & 0x017f & pData->u32Lnkst) ? 0x8000 : 0;
3004 break;
3005
3006 case BCR_MIIMDR:
3007 if (pData->fAm79C973 && (pData->aBCR[BCR_MIIADDR] >> 5 & 0x1f) == 0)
3008 {
3009 uint32_t miiaddr = pData->aBCR[BCR_MIIADDR] & 0x1f;
3010 val = pcnetMIIReadU16(pData, miiaddr);
3011 }
3012 else
3013 val = 0xffff;
3014 break;
3015
3016 default:
3017 val = u32RAP < BCR_MAX_RAP ? pData->aBCR[u32RAP] : 0;
3018 break;
3019 }
3020#ifdef PCNET_DEBUG_BCR
3021 Log2(("#%d pcnetBCRReadU16: rap=%d val=%#06x\n", PCNET_INST_NR, u32RAP, val));
3022#endif
3023 return val;
3024}
3025
3026#ifdef IN_RING3 /* move down */
3027static void pcnetHardReset(PCNetState *pData)
3028{
3029 int i;
3030 uint16_t checksum;
3031
3032 /* Initialize the PROM */
3033 Assert(sizeof(pData->MacConfigured) == 6);
3034 memcpy(pData->aPROM, &pData->MacConfigured, sizeof(pData->MacConfigured));
3035 pData->aPROM[ 8] = 0x00;
3036 pData->aPROM[ 9] = 0x11;
3037 pData->aPROM[12] = pData->aPROM[13] = 0x00;
3038 pData->aPROM[14] = pData->aPROM[15] = 0x57;
3039
3040 for (i = 0, checksum = 0; i < 16; i++)
3041 checksum += pData->aPROM[i];
3042 *(uint16_t *)&pData->aPROM[12] = RT_H2LE_U16(checksum);
3043
3044 pData->aBCR[BCR_MSRDA] = 0x0005;
3045 pData->aBCR[BCR_MSWRA] = 0x0005;
3046 pData->aBCR[BCR_MC ] = 0x0002;
3047 pData->aBCR[BCR_LNKST] = 0x00c0;
3048 pData->aBCR[BCR_LED1 ] = 0x0084;
3049 pData->aBCR[BCR_LED2 ] = 0x0088;
3050 pData->aBCR[BCR_LED3 ] = 0x0090;
3051 pData->aBCR[BCR_FDC ] = 0x0000;
3052 pData->aBCR[BCR_BSBC ] = 0x9001;
3053 pData->aBCR[BCR_EECAS] = 0x0002;
3054 pData->aBCR[BCR_STVAL] = 0xffff;
3055 pData->aCSR[58 ] = /* CSR58 is an alias for BCR20 */
3056 pData->aBCR[BCR_SWS ] = 0x0200;
3057 pData->iLog2DescSize = 3;
3058 pData->aBCR[BCR_PLAT ] = 0xff06;
3059 pData->aBCR[BCR_MIIADDR ] = 0; /* Internal PHY on Am79C973 would be (0x1e << 5) */
3060 pData->aBCR[BCR_PCIVID] = PCIDevGetVendorId(&pData->PciDev);
3061 pData->aBCR[BCR_PCISID] = PCIDevGetSubSystemId(&pData->PciDev);
3062 pData->aBCR[BCR_PCISVID] = PCIDevGetSubSystemVendorId(&pData->PciDev);
3063
3064 pcnetSoftReset(pData);
3065}
3066#endif /* IN_RING3 */
3067
3068static void pcnetAPROMWriteU8(PCNetState *pData, uint32_t addr, uint32_t val)
3069{
3070 addr &= 0x0f;
3071 val &= 0xff;
3072 Log(("#%d pcnetAPROMWriteU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val));
3073 /* Check APROMWE bit to enable write access */
3074 if (pcnetBCRReadU16(pData, 2) & 0x80)
3075 pData->aPROM[addr] = val;
3076}
3077
3078static uint32_t pcnetAPROMReadU8(PCNetState *pData, uint32_t addr)
3079{
3080 uint32_t val = pData->aPROM[addr &= 0x0f];
3081 Log(("#%d pcnetAPROMReadU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val));
3082 return val;
3083}
3084
3085static int pcnetIoportWriteU16(PCNetState *pData, uint32_t addr, uint32_t val)
3086{
3087 int rc = VINF_SUCCESS;
3088
3089#ifdef PCNET_DEBUG_IO
3090 Log2(("#%d pcnetIoportWriteU16: addr=%#010x val=%#06x\n", PCNET_INST_NR,
3091 addr, val));
3092#endif
3093 if (RT_LIKELY(!BCR_DWIO(pData)))
3094 {
3095 switch (addr & 0x0f)
3096 {
3097 case 0x00: /* RDP */
3098 pcnetPollTimer(pData);
3099 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val);
3100 pcnetUpdateIrq(pData);
3101 break;
3102 case 0x02: /* RAP */
3103 pData->u32RAP = val & 0x7f;
3104 break;
3105 case 0x06: /* BDP */
3106 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val);
3107 break;
3108 }
3109 }
3110 else
3111 Log(("#%d pcnetIoportWriteU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3112
3113 return rc;
3114}
3115
3116static uint32_t pcnetIoportReadU16(PCNetState *pData, uint32_t addr, int *pRC)
3117{
3118 uint32_t val = ~0U;
3119
3120 *pRC = VINF_SUCCESS;
3121
3122 if (RT_LIKELY(!BCR_DWIO(pData)))
3123 {
3124 switch (addr & 0x0f)
3125 {
3126 case 0x00: /* RDP */
3127 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
3128 /** Polling is then useless here and possibly expensive. */
3129 if (!CSR_DPOLL(pData))
3130 pcnetPollTimer(pData);
3131
3132 val = pcnetCSRReadU16(pData, pData->u32RAP);
3133 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
3134 goto skip_update_irq;
3135 break;
3136 case 0x02: /* RAP */
3137 val = pData->u32RAP;
3138 goto skip_update_irq;
3139 case 0x04: /* RESET */
3140 pcnetSoftReset(pData);
3141 val = 0;
3142 break;
3143 case 0x06: /* BDP */
3144 val = pcnetBCRReadU16(pData, pData->u32RAP);
3145 break;
3146 }
3147 }
3148 else
3149 Log(("#%d pcnetIoportReadU16: addr=%#010x val=%#06x BCR_DWIO !!\n", PCNET_INST_NR, addr, val & 0xffff));
3150
3151 pcnetUpdateIrq(pData);
3152
3153skip_update_irq:
3154#ifdef PCNET_DEBUG_IO
3155 Log2(("#%d pcnetIoportReadU16: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val & 0xffff));
3156#endif
3157 return val;
3158}
3159
3160static int pcnetIoportWriteU32(PCNetState *pData, uint32_t addr, uint32_t val)
3161{
3162 int rc = VINF_SUCCESS;
3163
3164#ifdef PCNET_DEBUG_IO
3165 Log2(("#%d pcnetIoportWriteU32: addr=%#010x val=%#010x\n", PCNET_INST_NR,
3166 addr, val));
3167#endif
3168 if (RT_LIKELY(BCR_DWIO(pData)))
3169 {
3170 switch (addr & 0x0f)
3171 {
3172 case 0x00: /* RDP */
3173 pcnetPollTimer(pData);
3174 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val & 0xffff);
3175 pcnetUpdateIrq(pData);
3176 break;
3177 case 0x04: /* RAP */
3178 pData->u32RAP = val & 0x7f;
3179 break;
3180 case 0x0c: /* BDP */
3181 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val & 0xffff);
3182 break;
3183 }
3184 }
3185 else if ((addr & 0x0f) == 0)
3186 {
3187 /* switch device to dword I/O mode */
3188 pcnetBCRWriteU16(pData, BCR_BSBC, pcnetBCRReadU16(pData, BCR_BSBC) | 0x0080);
3189#ifdef PCNET_DEBUG_IO
3190 Log2(("device switched into dword i/o mode\n"));
3191#endif
3192 }
3193 else
3194 Log(("#%d pcnetIoportWriteU32: addr=%#010x val=%#010x !BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3195
3196 return rc;
3197}
3198
3199static uint32_t pcnetIoportReadU32(PCNetState *pData, uint32_t addr, int *pRC)
3200{
3201 uint32_t val = ~0U;
3202
3203 *pRC = VINF_SUCCESS;
3204
3205 if (RT_LIKELY(BCR_DWIO(pData)))
3206 {
3207 switch (addr & 0x0f)
3208 {
3209 case 0x00: /* RDP */
3210 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
3211 /** Polling is then useless here and possibly expensive. */
3212 if (!CSR_DPOLL(pData))
3213 pcnetPollTimer(pData);
3214
3215 val = pcnetCSRReadU16(pData, pData->u32RAP);
3216 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
3217 goto skip_update_irq;
3218 break;
3219 case 0x04: /* RAP */
3220 val = pData->u32RAP;
3221 goto skip_update_irq;
3222 case 0x08: /* RESET */
3223 pcnetSoftReset(pData);
3224 val = 0;
3225 break;
3226 case 0x0c: /* BDP */
3227 val = pcnetBCRReadU16(pData, pData->u32RAP);
3228 break;
3229 }
3230 }
3231 else
3232 Log(("#%d pcnetIoportReadU32: addr=%#010x val=%#010x !BCR_DWIO !!\n", PCNET_INST_NR, addr, val));
3233 pcnetUpdateIrq(pData);
3234
3235skip_update_irq:
3236#ifdef PCNET_DEBUG_IO
3237 Log2(("#%d pcnetIoportReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
3238#endif
3239 return val;
3240}
3241
3242static void pcnetMMIOWriteU8(PCNetState *pData, RTGCPHYS addr, uint32_t val)
3243{
3244#ifdef PCNET_DEBUG_IO
3245 Log2(("#%d pcnetMMIOWriteU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val));
3246#endif
3247 if (!(addr & 0x10))
3248 pcnetAPROMWriteU8(pData, addr, val);
3249}
3250
3251static uint32_t pcnetMMIOReadU8(PCNetState *pData, RTGCPHYS addr)
3252{
3253 uint32_t val = ~0U;
3254 if (!(addr & 0x10))
3255 val = pcnetAPROMReadU8(pData, addr);
3256#ifdef PCNET_DEBUG_IO
3257 Log2(("#%d pcnetMMIOReadU8: addr=%#010x val=%#04x\n", PCNET_INST_NR, addr, val & 0xff));
3258#endif
3259 return val;
3260}
3261
3262static void pcnetMMIOWriteU16(PCNetState *pData, RTGCPHYS addr, uint32_t val)
3263{
3264#ifdef PCNET_DEBUG_IO
3265 Log2(("#%d pcnetMMIOWriteU16: addr=%#010x val=%#06x\n", PCNET_INST_NR, addr, val));
3266#endif
3267 if (addr & 0x10)
3268 pcnetIoportWriteU16(pData, addr & 0x0f, val);
3269 else
3270 {
3271 pcnetAPROMWriteU8(pData, addr, val );
3272 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
3273 }
3274}
3275
3276static uint32_t pcnetMMIOReadU16(PCNetState *pData, RTGCPHYS addr)
3277{
3278 uint32_t val = ~0U;
3279 int rc;
3280
3281 if (addr & 0x10)
3282 val = pcnetIoportReadU16(pData, addr & 0x0f, &rc);
3283 else
3284 {
3285 val = pcnetAPROMReadU8(pData, addr+1);
3286 val <<= 8;
3287 val |= pcnetAPROMReadU8(pData, addr);
3288 }
3289#ifdef PCNET_DEBUG_IO
3290 Log2(("#%d pcnetMMIOReadU16: addr=%#010x val = %#06x\n", PCNET_INST_NR, addr, val & 0xffff));
3291#endif
3292 return val;
3293}
3294
3295static void pcnetMMIOWriteU32(PCNetState *pData, RTGCPHYS addr, uint32_t val)
3296{
3297#ifdef PCNET_DEBUG_IO
3298 Log2(("#%d pcnetMMIOWriteU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
3299#endif
3300 if (addr & 0x10)
3301 pcnetIoportWriteU32(pData, addr & 0x0f, val);
3302 else
3303 {
3304 pcnetAPROMWriteU8(pData, addr, val );
3305 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
3306 pcnetAPROMWriteU8(pData, addr+2, val >> 16);
3307 pcnetAPROMWriteU8(pData, addr+3, val >> 24);
3308 }
3309}
3310
3311static uint32_t pcnetMMIOReadU32(PCNetState *pData, RTGCPHYS addr)
3312{
3313 uint32_t val;
3314 int rc;
3315
3316 if (addr & 0x10)
3317 val = pcnetIoportReadU32(pData, addr & 0x0f, &rc);
3318 else
3319 {
3320 val = pcnetAPROMReadU8(pData, addr+3);
3321 val <<= 8;
3322 val |= pcnetAPROMReadU8(pData, addr+2);
3323 val <<= 8;
3324 val |= pcnetAPROMReadU8(pData, addr+1);
3325 val <<= 8;
3326 val |= pcnetAPROMReadU8(pData, addr );
3327 }
3328#ifdef PCNET_DEBUG_IO
3329 Log2(("#%d pcnetMMIOReadU32: addr=%#010x val=%#010x\n", PCNET_INST_NR, addr, val));
3330#endif
3331 return val;
3332}
3333
3334
3335/**
3336 * Port I/O Handler for IN operations.
3337 *
3338 * @returns VBox status code.
3339 *
3340 * @param pDevIns The device instance.
3341 * @param pvUser User argument.
3342 * @param Port Port number used for the IN operation.
3343 * @param pu32 Where to store the result.
3344 * @param cb Number of bytes read.
3345 */
3346PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
3347 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3348{
3349 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3350 int rc;
3351
3352 STAM_PROFILE_ADV_START(&pData->StatAPROMRead, a);
3353 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3354 if (rc == VINF_SUCCESS)
3355 {
3356
3357 /* FreeBSD is accessing in dwords. */
3358 if (cb == 1)
3359 *pu32 = pcnetAPROMReadU8(pData, Port);
3360 else if (cb == 2 && !BCR_DWIO(pData))
3361 *pu32 = pcnetAPROMReadU8(pData, Port)
3362 | (pcnetAPROMReadU8(pData, Port + 1) << 8);
3363 else if (cb == 4 && BCR_DWIO(pData))
3364 *pu32 = pcnetAPROMReadU8(pData, Port)
3365 | (pcnetAPROMReadU8(pData, Port + 1) << 8)
3366 | (pcnetAPROMReadU8(pData, Port + 2) << 16)
3367 | (pcnetAPROMReadU8(pData, Port + 3) << 24);
3368 else
3369 {
3370 Log(("#%d pcnetIOPortAPromRead: Port=%RTiop cb=%d BCR_DWIO !!\n", PCNET_INST_NR, Port, cb));
3371 rc = VERR_IOM_IOPORT_UNUSED;
3372 }
3373 PDMCritSectLeave(&pData->CritSect);
3374 }
3375 STAM_PROFILE_ADV_STOP(&pData->StatAPROMRead, a);
3376 LogFlow(("#%d pcnetIOPortAPromRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n", PCNET_INST_NR, Port, *pu32, cb, rc));
3377 return rc;
3378}
3379
3380
3381/**
3382 * Port I/O Handler for OUT operations.
3383 *
3384 * @returns VBox status code.
3385 *
3386 * @param pDevIns The device instance.
3387 * @param pvUser User argument.
3388 * @param Port Port number used for the IN operation.
3389 * @param u32 The value to output.
3390 * @param cb The value size in bytes.
3391 */
3392PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
3393 RTIOPORT Port, uint32_t u32, unsigned cb)
3394{
3395 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3396 int rc;
3397
3398 if (cb == 1)
3399 {
3400 STAM_PROFILE_ADV_START(&pData->StatAPROMWrite, a);
3401 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3402 if (RT_LIKELY(rc == VINF_SUCCESS))
3403 {
3404 pcnetAPROMWriteU8(pData, Port, u32);
3405 PDMCritSectLeave(&pData->CritSect);
3406 }
3407 STAM_PROFILE_ADV_STOP(&pData->StatAPROMWrite, a);
3408 }
3409 else
3410 {
3411 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3412 rc = VINF_SUCCESS;
3413 }
3414 LogFlow(("#%d pcnetIOPortAPromWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n", PCNET_INST_NR, Port, u32, cb, rc));
3415#ifdef LOG_ENABLED
3416 if (rc == VINF_IOM_HC_IOPORT_WRITE)
3417 LogFlow(("#%d => HC\n", PCNET_INST_NR));
3418#endif
3419 return rc;
3420}
3421
3422
3423/**
3424 * Port I/O Handler for IN operations.
3425 *
3426 * @returns VBox status code.
3427 *
3428 * @param pDevIns The device instance.
3429 * @param pvUser User argument.
3430 * @param Port Port number used for the IN operation.
3431 * @param pu32 Where to store the result.
3432 * @param cb Number of bytes read.
3433 */
3434PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
3435 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3436{
3437 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3438 int rc = VINF_SUCCESS;
3439
3440 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIORead), a);
3441 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
3442 if (RT_LIKELY(rc == VINF_SUCCESS))
3443 {
3444 switch (cb)
3445 {
3446 case 2: *pu32 = pcnetIoportReadU16(pData, Port, &rc); break;
3447 case 4: *pu32 = pcnetIoportReadU32(pData, Port, &rc); break;
3448 default:
3449 rc = VERR_IOM_IOPORT_UNUSED;
3450 break;
3451 }
3452 PDMCritSectLeave(&pData->CritSect);
3453 }
3454 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIORead), a);
3455 Log2(("#%d pcnetIOPortRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n", PCNET_INST_NR, Port, *pu32, cb, rc));
3456#ifdef LOG_ENABLED
3457 if (rc == VINF_IOM_HC_IOPORT_READ)
3458 LogFlow(("#%d pcnetIOPortRead/critsect failed in GC => HC\n", PCNET_INST_NR));
3459#endif
3460 return rc;
3461}
3462
3463
3464/**
3465 * Port I/O Handler for OUT operations.
3466 *
3467 * @returns VBox status code.
3468 *
3469 * @param pDevIns The device instance.
3470 * @param pvUser User argument.
3471 * @param Port Port number used for the IN operation.
3472 * @param u32 The value to output.
3473 * @param cb The value size in bytes.
3474 */
3475PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
3476 RTIOPORT Port, uint32_t u32, unsigned cb)
3477{
3478 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3479 int rc = VINF_SUCCESS;
3480
3481 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIOWrite), a);
3482 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3483 if (RT_LIKELY(rc == VINF_SUCCESS))
3484 {
3485 switch (cb)
3486 {
3487 case 2: rc = pcnetIoportWriteU16(pData, Port, u32); break;
3488 case 4: rc = pcnetIoportWriteU32(pData, Port, u32); break;
3489 default:
3490 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3491 rc = VERR_INTERNAL_ERROR;
3492 break;
3493 }
3494 PDMCritSectLeave(&pData->CritSect);
3495 }
3496 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIOWrite), a);
3497 Log2(("#%d pcnetIOPortWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n", PCNET_INST_NR, Port, u32, cb, rc));
3498#ifdef LOG_ENABLED
3499 if (rc == VINF_IOM_HC_IOPORT_WRITE)
3500 LogFlow(("#%d pcnetIOPortWrite/critsect failed in GC => HC\n", PCNET_INST_NR));
3501#endif
3502 return rc;
3503}
3504
3505
3506/**
3507 * Memory mapped I/O Handler for read operations.
3508 *
3509 * @returns VBox status code.
3510 *
3511 * @param pDevIns The device instance.
3512 * @param pvUser User argument.
3513 * @param GCPhysAddr Physical address (in GC) where the read starts.
3514 * @param pv Where to store the result.
3515 * @param cb Number of bytes read.
3516 */
3517PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
3518 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3519{
3520 PCNetState *pData = (PCNetState *)pvUser;
3521 int rc = VINF_SUCCESS;
3522
3523 /*
3524 * We have to check the range, because we're page aligning the MMIO stuff presently.
3525 */
3526 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3527 {
3528 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIORead), a);
3529 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_READ);
3530 if (RT_LIKELY(rc == VINF_SUCCESS))
3531 {
3532 switch (cb)
3533 {
3534 case 1: *(uint8_t *)pv = pcnetMMIOReadU8 (pData, GCPhysAddr); break;
3535 case 2: *(uint16_t *)pv = pcnetMMIOReadU16(pData, GCPhysAddr); break;
3536 case 4: *(uint32_t *)pv = pcnetMMIOReadU32(pData, GCPhysAddr); break;
3537 default:
3538 AssertMsgFailed(("cb=%d\n", cb));
3539 rc = VERR_INTERNAL_ERROR;
3540 break;
3541 }
3542 PDMCritSectLeave(&pData->CritSect);
3543 }
3544 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIORead), a);
3545 }
3546 else
3547 memset(pv, 0, cb);
3548
3549 LogFlow(("#%d pcnetMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3550 PCNET_INST_NR, pv, cb, pv, cb, GCPhysAddr, rc));
3551#ifdef LOG_ENABLED
3552 if (rc == VINF_IOM_HC_MMIO_READ)
3553 LogFlow(("#%d => HC\n", PCNET_INST_NR));
3554#endif
3555 return rc;
3556}
3557
3558
3559/**
3560 * Port I/O Handler for write operations.
3561 *
3562 * @returns VBox status code.
3563 *
3564 * @param pDevIns The device instance.
3565 * @param pvUser User argument.
3566 * @param GCPhysAddr Physical address (in GC) where the read starts.
3567 * @param pv Where to fetch the result.
3568 * @param cb Number of bytes to write.
3569 */
3570PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
3571 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3572{
3573 PCNetState *pData = (PCNetState *)pvUser;
3574 int rc = VINF_SUCCESS;
3575
3576 /*
3577 * We have to check the range, because we're page aligning the MMIO stuff presently.
3578 */
3579 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3580 {
3581 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIOWrite), a);
3582 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_WRITE);
3583 if (RT_LIKELY(rc == VINF_SUCCESS))
3584 {
3585 switch (cb)
3586 {
3587 case 1: pcnetMMIOWriteU8 (pData, GCPhysAddr, *(uint8_t *)pv); break;
3588 case 2: pcnetMMIOWriteU16(pData, GCPhysAddr, *(uint16_t *)pv); break;
3589 case 4: pcnetMMIOWriteU32(pData, GCPhysAddr, *(uint32_t *)pv); break;
3590 default:
3591 AssertMsgFailed(("cb=%d\n", cb));
3592 rc = VERR_INTERNAL_ERROR;
3593 break;
3594 }
3595 PDMCritSectLeave(&pData->CritSect);
3596 }
3597 // else rc == VINF_IOM_HC_MMIO_WRITE => handle in ring3
3598
3599 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIOWrite), a);
3600 }
3601 LogFlow(("#%d pcnetMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3602 PCNET_INST_NR, pv, cb, pv, cb, GCPhysAddr, rc));
3603#ifdef LOG_ENABLED
3604 if (rc == VINF_IOM_HC_MMIO_WRITE)
3605 LogFlow(("#%d => HC\n", PCNET_INST_NR));
3606#endif
3607 return rc;
3608}
3609
3610
3611#ifdef IN_RING3
3612/**
3613 * Device timer callback function.
3614 *
3615 * @param pDevIns Device instance of the device which registered the timer.
3616 * @param pTimer The timer handle.
3617 * @thread EMT
3618 */
3619static DECLCALLBACK(void) pcnetTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3620{
3621 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3622 int rc;
3623
3624 STAM_PROFILE_ADV_START(&pData->StatTimer, a);
3625 rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
3626 AssertReleaseRC(rc);
3627
3628 pcnetPollTimer(pData);
3629
3630 PDMCritSectLeave(&pData->CritSect);
3631 STAM_PROFILE_ADV_STOP(&pData->StatTimer, a);
3632}
3633
3634
3635/**
3636 * Software interrupt timer callback function.
3637 *
3638 * @param pDevIns Device instance of the device which registered the timer.
3639 * @param pTimer The timer handle.
3640 * @thread EMT
3641 */
3642static DECLCALLBACK(void) pcnetTimerSoftInt(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3643{
3644 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3645
3646 pData->aCSR[7] |= 0x0800; /* STINT */
3647 pcnetUpdateIrq(pData);
3648 TMTimerSetNano(pData->CTXSUFF(pTimerSoftInt), 12800U * (pData->aBCR[BCR_STVAL] & 0xffff));
3649}
3650
3651
3652/**
3653 * Restore timer callback.
3654 *
3655 * This is only called when've restored a saved state and temporarily
3656 * disconnected the network link to inform the guest that network connections
3657 * should be considered lost.
3658 *
3659 * @param pDevIns Device instance of the device which registered the timer.
3660 * @param pTimer The timer handle.
3661 */
3662static DECLCALLBACK(void) pcnetTimerRestore(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3663{
3664 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3665 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
3666 AssertReleaseRC(rc);
3667
3668 rc = VERR_GENERAL_FAILURE;
3669 if (pData->cLinkDownReported <= PCNET_MAX_LINKDOWN_REPORTED)
3670 rc = TMTimerSetMillies(pData->pTimerRestore, 1500);
3671 if (VBOX_FAILURE(rc))
3672 {
3673 pData->fLinkTempDown = false;
3674 if (pData->fLinkUp)
3675 {
3676 LogRel(("PCNet#%d: The link is back up again after the restore.\n",
3677 pDevIns->iInstance));
3678 Log(("#%d pcnetTimerRestore: Clearing ERR and CERR after load. cLinkDownReported=%d\n",
3679 pDevIns->iInstance, pData->cLinkDownReported));
3680 pData->aCSR[0] &= ~(RT_BIT(15) | RT_BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3681 pData->Led.Actual.s.fError = 0;
3682 }
3683 }
3684 else
3685 Log(("#%d pcnetTimerRestore: cLinkDownReported=%d, wait another 1500ms...\n",
3686 pDevIns->iInstance, pData->cLinkDownReported));
3687
3688 PDMCritSectLeave(&pData->CritSect);
3689}
3690
3691
3692/**
3693 * Callback function for mapping an PCI I/O region.
3694 *
3695 * @return VBox status code.
3696 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3697 * @param iRegion The region number.
3698 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3699 * I/O port, else it's a physical address.
3700 * This address is *NOT* relative to pci_mem_base like earlier!
3701 * @param cb Region size.
3702 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3703 */
3704static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3705 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3706{
3707 int rc;
3708 PPDMDEVINS pDevIns = pPciDev->pDevIns;
3709 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
3710 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3711
3712 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3713 Assert(cb >= 0x20);
3714
3715 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 0x10, 0, pcnetIOPortAPromWrite,
3716 pcnetIOPortAPromRead, NULL, NULL, "PCNet ARPOM");
3717 if (VBOX_FAILURE(rc))
3718 return rc;
3719 rc = PDMDevHlpIOPortRegister(pDevIns, Port + 0x10, 0x10, 0, pcnetIOPortWrite,
3720 pcnetIOPortRead, NULL, NULL, "PCNet");
3721 if (VBOX_FAILURE(rc))
3722 return rc;
3723
3724 if (pData->fGCEnabled)
3725 {
3726 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3727 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3728 if (VBOX_FAILURE(rc))
3729 return rc;
3730 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3731 "pcnetIOPortRead", NULL, NULL, "PCNet");
3732 if (VBOX_FAILURE(rc))
3733 return rc;
3734 }
3735 if (pData->fR0Enabled)
3736 {
3737 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3738 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3739 if (VBOX_FAILURE(rc))
3740 return rc;
3741 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3742 "pcnetIOPortRead", NULL, NULL, "PCNet");
3743 if (VBOX_FAILURE(rc))
3744 return rc;
3745 }
3746
3747 pData->IOPortBase = Port;
3748 return VINF_SUCCESS;
3749}
3750
3751
3752/**
3753 * Callback function for mapping the MMIO region.
3754 *
3755 * @return VBox status code.
3756 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3757 * @param iRegion The region number.
3758 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3759 * I/O port, else it's a physical address.
3760 * This address is *NOT* relative to pci_mem_base like earlier!
3761 * @param cb Region size.
3762 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3763 */
3764static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3765 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3766{
3767 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3768 int rc;
3769
3770 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
3771 Assert(cb >= PCNET_PNPMMIO_SIZE);
3772
3773 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3774 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pData,
3775 pcnetMMIOWrite, pcnetMMIORead, NULL, "PCNet");
3776 if (VBOX_FAILURE(rc))
3777 return rc;
3778 pData->MMIOBase = GCPhysAddress;
3779 return rc;
3780}
3781
3782
3783/**
3784 * Callback function for mapping the MMIO region.
3785 *
3786 * @return VBox status code.
3787 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3788 * @param iRegion The region number.
3789 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3790 * I/O port, else it's a physical address.
3791 * This address is *NOT* relative to pci_mem_base like earlier!
3792 * @param cb Region size.
3793 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3794 */
3795static DECLCALLBACK(int) pcnetMMIOSharedMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3796 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3797{
3798 if (GCPhysAddress != NIL_RTGCPHYS)
3799 return PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
3800
3801 /* nothing to clean up */
3802 return VINF_SUCCESS;
3803}
3804
3805
3806/**
3807 * PCNET status info callback.
3808 *
3809 * @param pDevIns The device instance.
3810 * @param pHlp The output helpers.
3811 * @param pszArgs The arguments.
3812 */
3813static DECLCALLBACK(void) pcnetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3814{
3815 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3816 bool fRcvRing = false;
3817 bool fXmtRing = false;
3818
3819 /*
3820 * Parse args.
3821 */
3822 if (pszArgs)
3823 {
3824 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
3825 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
3826 }
3827
3828 /*
3829 * Show info.
3830 */
3831 pHlp->pfnPrintf(pHlp,
3832 "pcnet #%d: port=%RTiop mmio=%RGp mac-cfg=%.*Rhxs %s\n",
3833 pDevIns->iInstance,
3834 pData->IOPortBase, pData->MMIOBase, sizeof(pData->MacConfigured), &pData->MacConfigured,
3835 pData->fAm79C973 ? "Am79C973" : "Am79C970A", pData->fGCEnabled ? " GC" : "", pData->fR0Enabled ? " R0" : "");
3836
3837 PDMCritSectEnter(&pData->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
3838
3839 pHlp->pfnPrintf(pHlp,
3840 "CSR0=%#06x:\n",
3841 pData->aCSR[0]);
3842
3843 pHlp->pfnPrintf(pHlp,
3844 "CSR1=%#06x:\n",
3845 pData->aCSR[1]);
3846
3847 pHlp->pfnPrintf(pHlp,
3848 "CSR2=%#06x:\n",
3849 pData->aCSR[2]);
3850
3851 pHlp->pfnPrintf(pHlp,
3852 "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",
3853 pData->aCSR[3],
3854 !!(pData->aCSR[3] & RT_BIT(2)), !!(pData->aCSR[3] & RT_BIT(3)), !!(pData->aCSR[3] & RT_BIT(4)), CSR_LAPPEN(pData),
3855 CSR_DXSUFLO(pData), !!(pData->aCSR[3] & RT_BIT(8)), !!(pData->aCSR[3] & RT_BIT(9)), !!(pData->aCSR[3] & RT_BIT(10)),
3856 !!(pData->aCSR[3] & RT_BIT(11)), !!(pData->aCSR[3] & RT_BIT(12)), !!(pData->aCSR[3] & RT_BIT(14)));
3857
3858 pHlp->pfnPrintf(pHlp,
3859 "CSR4=%#06x: JABM=%d JAB=%d TXSTRM=%d TXSTRT=%d RCVCOOM=%d RCVCCO=%d UINT=%d UINTCMD=%d\n"
3860 " MFCOM=%d MFCO=%d ASTRP_RCV=%d APAD_XMT=%d DPOLL=%d TIMER=%d EMAPLUS=%d EN124=%d\n",
3861 pData->aCSR[4],
3862 !!(pData->aCSR[4] & RT_BIT( 0)), !!(pData->aCSR[4] & RT_BIT( 1)), !!(pData->aCSR[4] & RT_BIT( 2)), !!(pData->aCSR[4] & RT_BIT( 3)),
3863 !!(pData->aCSR[4] & RT_BIT( 4)), !!(pData->aCSR[4] & RT_BIT( 5)), !!(pData->aCSR[4] & RT_BIT( 6)), !!(pData->aCSR[4] & RT_BIT( 7)),
3864 !!(pData->aCSR[4] & RT_BIT( 8)), !!(pData->aCSR[4] & RT_BIT( 9)), !!(pData->aCSR[4] & RT_BIT(10)), !!(pData->aCSR[4] & RT_BIT(11)),
3865 !!(pData->aCSR[4] & RT_BIT(12)), !!(pData->aCSR[4] & RT_BIT(13)), !!(pData->aCSR[4] & RT_BIT(14)), !!(pData->aCSR[4] & RT_BIT(15)));
3866
3867 pHlp->pfnPrintf(pHlp,
3868 "CSR5=%#06x:\n",
3869 pData->aCSR[5]);
3870
3871 pHlp->pfnPrintf(pHlp,
3872 "CSR6=%#06x: RLEN=%#x* TLEN=%#x* [* encoded]\n",
3873 pData->aCSR[6],
3874 (pData->aCSR[6] >> 8) & 0xf, (pData->aCSR[6] >> 12) & 0xf);
3875
3876 pHlp->pfnPrintf(pHlp,
3877 "CSR8..11=%#06x,%#06x,%#06x,%#06x: LADRF=%#018llx\n",
3878 pData->aCSR[8], pData->aCSR[9], pData->aCSR[10], pData->aCSR[11],
3879 (uint64_t)(pData->aCSR[ 8] & 0xffff)
3880 | (uint64_t)(pData->aCSR[ 9] & 0xffff) << 16
3881 | (uint64_t)(pData->aCSR[10] & 0xffff) << 32
3882 | (uint64_t)(pData->aCSR[11] & 0xffff) << 48);
3883
3884 pHlp->pfnPrintf(pHlp,
3885 "CSR12..14=%#06x,%#06x,%#06x: PADR=%02x:%02x:%02x:%02x:%02x:%02x (Current MAC Address)\n",
3886 pData->aCSR[12], pData->aCSR[13], pData->aCSR[14],
3887 pData->aCSR[12] & 0xff,
3888 (pData->aCSR[12] >> 8) & 0xff,
3889 pData->aCSR[13] & 0xff,
3890 (pData->aCSR[13] >> 8) & 0xff,
3891 pData->aCSR[14] & 0xff,
3892 (pData->aCSR[14] >> 8) & 0xff);
3893
3894 pHlp->pfnPrintf(pHlp,
3895 "CSR15=%#06x: DXR=%d DTX=%d LOOP=%d DXMTFCS=%d FCOLL=%d DRTY=%d INTL=%d PORTSEL=%d LTR=%d\n"
3896 " MENDECL=%d DAPC=%d DLNKTST=%d DRCVPV=%d DRCVBC=%d PROM=%d\n",
3897 pData->aCSR[15],
3898 !!(pData->aCSR[15] & RT_BIT( 0)), !!(pData->aCSR[15] & RT_BIT( 1)), !!(pData->aCSR[15] & RT_BIT( 2)), !!(pData->aCSR[15] & RT_BIT( 3)),
3899 !!(pData->aCSR[15] & RT_BIT( 4)), !!(pData->aCSR[15] & RT_BIT( 5)), !!(pData->aCSR[15] & RT_BIT( 6)), (pData->aCSR[15] >> 7) & 3,
3900 !!(pData->aCSR[15] & RT_BIT( 9)), !!(pData->aCSR[15] & RT_BIT(10)), !!(pData->aCSR[15] & RT_BIT(11)),
3901 !!(pData->aCSR[15] & RT_BIT(12)), !!(pData->aCSR[15] & RT_BIT(13)), !!(pData->aCSR[15] & RT_BIT(14)), !!(pData->aCSR[15] & RT_BIT(15)));
3902
3903 pHlp->pfnPrintf(pHlp,
3904 "CSR46=%#06x: POLL=%#06x (Poll Time Counter)\n",
3905 pData->aCSR[46], pData->aCSR[46] & 0xffff);
3906
3907 pHlp->pfnPrintf(pHlp,
3908 "CSR47=%#06x: POLLINT=%#06x (Poll Time Interval)\n",
3909 pData->aCSR[47], pData->aCSR[47] & 0xffff);
3910
3911 pHlp->pfnPrintf(pHlp,
3912 "CSR58=%#06x: SWSTYLE=%d %s SSIZE32=%d CSRPCNET=%d APERRENT=%d\n",
3913 pData->aCSR[58],
3914 pData->aCSR[58] & 0x7f,
3915 (pData->aCSR[58] & 0x7f) == 0 ? "C-LANCE / PCnet-ISA"
3916 : (pData->aCSR[58] & 0x7f) == 1 ? "ILACC"
3917 : (pData->aCSR[58] & 0x7f) == 2 ? "PCNet-PCI II"
3918 : (pData->aCSR[58] & 0x7f) == 3 ? "PCNet-PCI II controller"
3919 : "!!reserved!!",
3920 !!(pData->aCSR[58] & RT_BIT(8)), !!(pData->aCSR[58] & RT_BIT(9)), !!(pData->aCSR[58] & RT_BIT(10)));
3921
3922 pHlp->pfnPrintf(pHlp,
3923 "CSR112=%04RX32: MFC=%04x (Missed receive Frame Count)\n",
3924 pData->aCSR[112], pData->aCSR[112] & 0xffff);
3925
3926 pHlp->pfnPrintf(pHlp,
3927 "CSR122=%04RX32: RCVALGN=%04x (Receive Frame Align)\n",
3928 pData->aCSR[122], !!(pData->aCSR[122] & RT_BIT(0)));
3929
3930 pHlp->pfnPrintf(pHlp,
3931 "CSR124=%04RX32: RPA=%04x (Runt Packet Accept)\n",
3932 pData->aCSR[122], !!(pData->aCSR[122] & RT_BIT(3)));
3933
3934
3935 /*
3936 * Dump the receive ring.
3937 */
3938 pHlp->pfnPrintf(pHlp,
3939 "RCVRL=%04x RCVRC=%04x GCRDRA=%RX32 \n"
3940 "CRDA=%08RX32 CRBA=%08RX32 CRBC=%03x CRST=%04x\n"
3941 "NRDA=%08RX32 NRBA=%08RX32 NRBC=%03x NRST=%04x\n"
3942 "NNRDA=%08RX32\n"
3943 ,
3944 CSR_RCVRL(pData), CSR_RCVRC(pData), pData->GCRDRA,
3945 CSR_CRDA(pData), CSR_CRBA(pData), CSR_CRBC(pData), CSR_CRST(pData),
3946 CSR_NRDA(pData), CSR_NRBA(pData), CSR_NRBC(pData), CSR_NRST(pData),
3947 CSR_NNRD(pData));
3948 if (fRcvRing)
3949 {
3950 const unsigned cb = 1 << pData->iLog2DescSize;
3951 RTGCPHYS32 GCPhys = pData->GCRDRA;
3952 unsigned i = CSR_RCVRL(pData);
3953 while (i-- > 0)
3954 {
3955 RMD rmd;
3956 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys), false);
3957 pHlp->pfnPrintf(pHlp,
3958 "%04x %RGp:%c%c RBADR=%08RX32 BCNT=%03x MCNT=%03x "
3959 "OWN=%d ERR=%d FRAM=%d OFLO=%d CRC=%d BUFF=%d STP=%d ENP=%d BPE=%d "
3960 "PAM=%d LAFM=%d BAM=%d RCC=%02x RPC=%02x ONES=%#x ZEROS=%d\n",
3961 i, GCPhys, i + 1 == CSR_RCVRC(pData) ? '*' : ' ', GCPhys == CSR_CRDA(pData) ? '*' : ' ',
3962 rmd.rmd0.rbadr, 4096 - rmd.rmd1.bcnt, rmd.rmd2.mcnt,
3963 rmd.rmd1.own, rmd.rmd1.err, rmd.rmd1.fram, rmd.rmd1.oflo, rmd.rmd1.crc, rmd.rmd1.buff,
3964 rmd.rmd1.stp, rmd.rmd1.enp, rmd.rmd1.bpe,
3965 rmd.rmd1.pam, rmd.rmd1.lafm, rmd.rmd1.bam, rmd.rmd2.rcc, rmd.rmd2.rpc,
3966 rmd.rmd1.ones, rmd.rmd2.zeros);
3967
3968 GCPhys += cb;
3969 }
3970 }
3971
3972 /*
3973 * Dump the transmit ring.
3974 */
3975 pHlp->pfnPrintf(pHlp,
3976 "XMTRL=%04x XMTRC=%04x GCTDRA=%08RX32 BADX=%08RX32\n"
3977 "PXDA=%08RX32 PXBC=%03x PXST=%04x\n"
3978 "CXDA=%08RX32 CXBA=%08RX32 CXBC=%03x CXST=%04x\n"
3979 "NXDA=%08RX32 NXBA=%08RX32 NXBC=%03x NXST=%04x\n"
3980 "NNXDA=%08RX32\n"
3981 ,
3982 CSR_XMTRL(pData), CSR_XMTRC(pData),
3983 pData->GCTDRA, CSR_BADX(pData),
3984 CSR_PXDA(pData), CSR_PXBC(pData), CSR_PXST(pData),
3985 CSR_CXDA(pData), CSR_CXBA(pData), CSR_CXBC(pData), CSR_CXST(pData),
3986 CSR_NXDA(pData), CSR_NXBA(pData), CSR_NXBC(pData), CSR_NXST(pData),
3987 CSR_NNXD(pData));
3988 if (fXmtRing)
3989 {
3990 const unsigned cb = 1 << pData->iLog2DescSize;
3991 RTGCPHYS32 GCPhys = pData->GCTDRA;
3992 unsigned i = CSR_XMTRL(pData);
3993 while (i-- > 0)
3994 {
3995 TMD tmd;
3996 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, GCPhys), false);
3997 pHlp->pfnPrintf(pHlp,
3998 "%04x %RGp:%c%c TBADR=%08RX32 BCNT=%03x OWN=%d "
3999 "ERR=%d NOFCS=%d LTINT=%d ONE=%d DEF=%d STP=%d ENP=%d BPE=%d "
4000 "BUFF=%d UFLO=%d EXDEF=%d LCOL=%d LCAR=%d RTRY=%d TDR=%03x TRC=%#x ONES=%#x\n"
4001 ,
4002 i, GCPhys, i + 1 == CSR_XMTRC(pData) ? '*' : ' ', GCPhys == CSR_CXDA(pData) ? '*' : ' ',
4003 tmd.tmd0.tbadr, 4096 - tmd.tmd1.bcnt,
4004 tmd.tmd2.tdr,
4005 tmd.tmd2.trc,
4006 tmd.tmd1.own,
4007 tmd.tmd1.err,
4008 tmd.tmd1.nofcs,
4009 tmd.tmd1.ltint,
4010 tmd.tmd1.one,
4011 tmd.tmd1.def,
4012 tmd.tmd1.stp,
4013 tmd.tmd1.enp,
4014 tmd.tmd1.bpe,
4015 tmd.tmd2.buff,
4016 tmd.tmd2.uflo,
4017 tmd.tmd2.exdef,
4018 tmd.tmd2.lcol,
4019 tmd.tmd2.lcar,
4020 tmd.tmd2.rtry,
4021 tmd.tmd2.tdr,
4022 tmd.tmd2.trc,
4023 tmd.tmd1.ones);
4024
4025 GCPhys += cb;
4026 }
4027 }
4028
4029 PDMCritSectLeave(&pData->CritSect);
4030}
4031
4032
4033/**
4034 * Serializes the receive thread, it may be working inside the critsect.
4035 *
4036 * @returns VBox status code.
4037 * @param pDevIns The device instance.
4038 * @param pSSMHandle The handle to save the state to.
4039 */
4040static DECLCALLBACK(int) pcnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
4041{
4042 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4043
4044 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
4045 AssertRC(rc);
4046 PDMCritSectLeave(&pData->CritSect);
4047
4048 return VINF_SUCCESS;
4049}
4050
4051
4052/**
4053 * Saves a state of the PC-Net II device.
4054 *
4055 * @returns VBox status code.
4056 * @param pDevIns The device instance.
4057 * @param pSSMHandle The handle to save the state to.
4058 */
4059static DECLCALLBACK(int) pcnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
4060{
4061 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4062 int rc = VINF_SUCCESS;
4063
4064 SSMR3PutBool(pSSMHandle, pData->fLinkUp);
4065 SSMR3PutU32(pSSMHandle, pData->u32RAP);
4066 SSMR3PutS32(pSSMHandle, pData->iISR);
4067 SSMR3PutU32(pSSMHandle, pData->u32Lnkst);
4068 SSMR3PutBool(pSSMHandle, pData->fPrivIfEnabled);
4069 SSMR3PutGCPhys32(pSSMHandle, pData->GCRDRA);
4070 SSMR3PutGCPhys32(pSSMHandle, pData->GCTDRA);
4071 SSMR3PutMem(pSSMHandle, pData->aPROM, sizeof(pData->aPROM));
4072 SSMR3PutMem(pSSMHandle, pData->aCSR, sizeof(pData->aCSR));
4073 SSMR3PutMem(pSSMHandle, pData->aBCR, sizeof(pData->aBCR));
4074 SSMR3PutMem(pSSMHandle, pData->aMII, sizeof(pData->aMII));
4075 SSMR3PutU16(pSSMHandle, pData->u16CSR0LastSeenByGuest);
4076 SSMR3PutU64(pSSMHandle, pData->u64LastPoll);
4077 SSMR3PutMem(pSSMHandle, &pData->MacConfigured, sizeof(pData->MacConfigured));
4078 SSMR3PutBool(pSSMHandle, pData->fAm79C973);
4079 SSMR3PutU32(pSSMHandle, pData->u32LinkSpeed);
4080#ifdef PCNET_NO_POLLING
4081 return VINF_SUCCESS;
4082#else
4083 rc = TMR3TimerSave(pData->CTXSUFF(pTimerPoll), pSSMHandle);
4084 if (VBOX_FAILURE(rc))
4085 return rc;
4086#endif
4087 if (pData->fAm79C973)
4088 rc = TMR3TimerSave(pData->CTXSUFF(pTimerSoftInt), pSSMHandle);
4089 return rc;
4090}
4091
4092
4093/**
4094 * Serializes the receive thread, it may be working inside the critsect.
4095 *
4096 * @returns VBox status code.
4097 * @param pDevIns The device instance.
4098 * @param pSSMHandle The handle to save the state to.
4099 */
4100static DECLCALLBACK(int) pcnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
4101{
4102 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4103
4104 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
4105 AssertRC(rc);
4106 PDMCritSectLeave(&pData->CritSect);
4107
4108 return VINF_SUCCESS;
4109}
4110
4111
4112/**
4113 * Loads a saved PC-Net II device state.
4114 *
4115 * @returns VBox status code.
4116 * @param pDevIns The device instance.
4117 * @param pSSMHandle The handle to the saved state.
4118 * @param u32Version The data unit version number.
4119 */
4120static DECLCALLBACK(int) pcnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
4121{
4122 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4123 PDMMAC Mac;
4124 if (SSM_VERSION_MAJOR_CHANGED(u32Version, PCNET_SAVEDSTATE_VERSION))
4125 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4126
4127 /* restore data */
4128 SSMR3GetBool(pSSMHandle, &pData->fLinkUp);
4129 SSMR3GetU32(pSSMHandle, &pData->u32RAP);
4130 SSMR3GetS32(pSSMHandle, &pData->iISR);
4131 SSMR3GetU32(pSSMHandle, &pData->u32Lnkst);
4132 if ( SSM_VERSION_MAJOR(u32Version) > 0
4133 || SSM_VERSION_MINOR(u32Version) >= 9)
4134 {
4135 SSMR3GetBool(pSSMHandle, &pData->fPrivIfEnabled);
4136 if (pData->fPrivIfEnabled)
4137 LogRel(("PCNet#%d: Enabling private interface\n", PCNET_INST_NR));
4138 }
4139 SSMR3GetGCPhys32(pSSMHandle, &pData->GCRDRA);
4140 SSMR3GetGCPhys32(pSSMHandle, &pData->GCTDRA);
4141 SSMR3GetMem(pSSMHandle, &pData->aPROM, sizeof(pData->aPROM));
4142 SSMR3GetMem(pSSMHandle, &pData->aCSR, sizeof(pData->aCSR));
4143 SSMR3GetMem(pSSMHandle, &pData->aBCR, sizeof(pData->aBCR));
4144 SSMR3GetMem(pSSMHandle, &pData->aMII, sizeof(pData->aMII));
4145 SSMR3GetU16(pSSMHandle, &pData->u16CSR0LastSeenByGuest);
4146 SSMR3GetU64(pSSMHandle, &pData->u64LastPoll);
4147 SSMR3GetMem(pSSMHandle, &Mac, sizeof(Mac));
4148 Assert( !memcmp(&Mac, &pData->MacConfigured, sizeof(Mac))
4149 || SSMR3HandleGetAfter(pSSMHandle) == SSMAFTER_DEBUG_IT);
4150 SSMR3GetBool(pSSMHandle, &pData->fAm79C973);
4151 SSMR3GetU32(pSSMHandle, &pData->u32LinkSpeed);
4152#ifndef PCNET_NO_POLLING
4153 TMR3TimerLoad(pData->CTXSUFF(pTimerPoll), pSSMHandle);
4154#endif
4155 if (pData->fAm79C973)
4156 {
4157 if ( SSM_VERSION_MAJOR(u32Version) > 0
4158 || SSM_VERSION_MINOR(u32Version) >= 8)
4159 TMR3TimerLoad(pData->CTXSUFF(pTimerSoftInt), pSSMHandle);
4160 }
4161
4162 pData->iLog2DescSize = BCR_SWSTYLE(pData)
4163 ? 4
4164 : 3;
4165 pData->GCUpperPhys = BCR_SSIZE32(pData)
4166 ? 0
4167 : (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
4168
4169 /* update promiscuous mode. */
4170 if (pData->pDrv)
4171 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
4172
4173#ifdef PCNET_NO_POLLING
4174 /* Enable physical monitoring again (!) */
4175 pcnetUpdateRingHandlers(pData);
4176#endif
4177 /* Indicate link down to the guest OS that all network connections have been lost. */
4178 if (pData->fLinkUp)
4179 {
4180 pData->fLinkTempDown = true;
4181 pData->cLinkDownReported = 0;
4182 pData->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR (this is probably wrong) */
4183 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
4184 return TMTimerSetMillies(pData->pTimerRestore, 5000);
4185 }
4186 return VINF_SUCCESS;
4187}
4188
4189
4190/**
4191 * Queries an interface to the driver.
4192 *
4193 * @returns Pointer to interface.
4194 * @returns NULL if the interface was not supported by the driver.
4195 * @param pInterface Pointer to this interface structure.
4196 * @param enmInterface The requested interface identification.
4197 * @thread Any thread.
4198 */
4199static DECLCALLBACK(void *) pcnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
4200{
4201 PCNetState *pData = (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, IBase));
4202 Assert(&pData->IBase == pInterface);
4203 switch (enmInterface)
4204 {
4205 case PDMINTERFACE_BASE:
4206 return &pData->IBase;
4207 case PDMINTERFACE_NETWORK_PORT:
4208 return &pData->INetworkPort;
4209 case PDMINTERFACE_NETWORK_CONFIG:
4210 return &pData->INetworkConfig;
4211 case PDMINTERFACE_LED_PORTS:
4212 return &pData->ILeds;
4213 default:
4214 return NULL;
4215 }
4216}
4217
4218/** Converts a pointer to PCNetState::INetworkPort to a PCNetState pointer. */
4219#define INETWORKPORT_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkPort)) )
4220
4221
4222/**
4223 * Check if the device/driver can receive data now.
4224 * This must be called before the pfnRecieve() method is called.
4225 *
4226 * @returns Number of bytes the driver can receive.
4227 * @param pInterface Pointer to the interface structure containing the called function pointer.
4228 * @thread EMT
4229 */
4230static DECLCALLBACK(size_t) pcnetCanReceive(PPDMINETWORKPORT pInterface)
4231{
4232 size_t cb = 0;
4233 int rc;
4234 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
4235
4236 rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
4237 AssertReleaseRC(rc);
4238
4239 if (RT_LIKELY(!CSR_DRX(pData) && !CSR_STOP(pData) && !CSR_SPND(pData)))
4240 {
4241 if (HOST_IS_OWNER(CSR_CRST(pData)) && pData->GCRDRA)
4242 pcnetRdtePoll(pData);
4243
4244 if (HOST_IS_OWNER(CSR_CRST(pData)))
4245 {
4246 /** @todo Notify the guest _now_. Will potentially increase the interrupt load */
4247 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
4248 }
4249 else
4250 {
4251 /* byte count stored in two's complement 12 bits wide */
4252 Log(("#%d pcnetCanReceiveNoSync %d bytes\n", PCNET_INST_NR, 4096 - CSR_CRBC(pData)));
4253 cb = 4096 - CSR_CRBC(pData);
4254 }
4255 }
4256
4257 PDMCritSectLeave(&pData->CritSect);
4258 return cb;
4259}
4260
4261
4262/**
4263 * Receive data from the network.
4264 *
4265 * @returns VBox status code.
4266 * @param pInterface Pointer to the interface structure containing the called function pointer.
4267 * @param pvBuf The available data.
4268 * @param cb Number of bytes available in the buffer.
4269 * @thread EMT
4270 */
4271static DECLCALLBACK(int) pcnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
4272{
4273 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
4274 int rc;
4275
4276 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
4277 rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
4278 AssertReleaseRC(rc);
4279
4280 if (cb > 70) /* unqualified guess */
4281 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
4282 pcnetReceiveNoSync(pData, (const uint8_t *)pvBuf, cb);
4283 pData->Led.Actual.s.fReading = 0;
4284
4285 PDMCritSectLeave(&pData->CritSect);
4286 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
4287
4288 return VINF_SUCCESS;
4289}
4290
4291/** Converts a pointer to PCNetState::INetworkConfig to a PCNetState pointer. */
4292#define INETWORKCONFIG_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkConfig)) )
4293
4294
4295/**
4296 * Gets the current Media Access Control (MAC) address.
4297 *
4298 * @returns VBox status code.
4299 * @param pInterface Pointer to the interface structure containing the called function pointer.
4300 * @param pMac Where to store the MAC address.
4301 * @thread EMT
4302 */
4303static DECLCALLBACK(int) pcnetGetMac(PPDMINETWORKCONFIG pInterface, PPDMMAC *pMac)
4304{
4305 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
4306 memcpy(pMac, pData->aPROM, sizeof(*pMac));
4307 return VINF_SUCCESS;
4308}
4309
4310
4311/**
4312 * Gets the new link state.
4313 *
4314 * @returns The current link state.
4315 * @param pInterface Pointer to the interface structure containing the called function pointer.
4316 * @thread EMT
4317 */
4318static DECLCALLBACK(PDMNETWORKLINKSTATE) pcnetGetLinkState(PPDMINETWORKCONFIG pInterface)
4319{
4320 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
4321 if (pData->fLinkUp && !pData->fLinkTempDown)
4322 return PDMNETWORKLINKSTATE_UP;
4323 if (!pData->fLinkUp)
4324 return PDMNETWORKLINKSTATE_DOWN;
4325 if (pData->fLinkTempDown)
4326 return PDMNETWORKLINKSTATE_DOWN_RESUME;
4327 AssertMsgFailed(("Invalid link state!\n"));
4328 return PDMNETWORKLINKSTATE_INVALID;
4329}
4330
4331
4332/**
4333 * Sets the new link state.
4334 *
4335 * @returns VBox status code.
4336 * @param pInterface Pointer to the interface structure containing the called function pointer.
4337 * @param enmState The new link state
4338 * @thread EMT
4339 */
4340static DECLCALLBACK(int) pcnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
4341{
4342 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
4343 bool fLinkUp;
4344 if ( enmState != PDMNETWORKLINKSTATE_DOWN
4345 && enmState != PDMNETWORKLINKSTATE_UP)
4346 {
4347 AssertMsgFailed(("Invalid parameter enmState=%d\n", enmState));
4348 return VERR_INVALID_PARAMETER;
4349 }
4350
4351 /* has the state changed? */
4352 fLinkUp = enmState == PDMNETWORKLINKSTATE_UP;
4353 if (pData->fLinkUp != fLinkUp)
4354 {
4355 pData->fLinkUp = fLinkUp;
4356 if (fLinkUp)
4357 {
4358 /* connect */
4359 pData->aCSR[0] &= ~(RT_BIT(15) | RT_BIT(13)); /* ERR | CERR - probably not 100% correct either... */
4360 pData->Led.Actual.s.fError = 0;
4361 }
4362 else
4363 {
4364 /* disconnect */
4365 pData->cLinkDownReported = 0;
4366 pData->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR (this is probably wrong) */
4367 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
4368 }
4369 Assert(!PDMCritSectIsOwner(&pData->CritSect));
4370 pData->pDrv->pfnNotifyLinkChanged(pData->pDrv, enmState);
4371 }
4372 return VINF_SUCCESS;
4373}
4374
4375
4376/**
4377 * Gets the pointer to the status LED of a unit.
4378 *
4379 * @returns VBox status code.
4380 * @param pInterface Pointer to the interface structure containing the called function pointer.
4381 * @param iLUN The unit which status LED we desire.
4382 * @param ppLed Where to store the LED pointer.
4383 */
4384static DECLCALLBACK(int) pcnetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4385{
4386 PCNetState *pData = (PCNetState *)( (uintptr_t)pInterface - RT_OFFSETOF(PCNetState, ILeds) );
4387 if (iLUN == 0)
4388 {
4389 *ppLed = &pData->Led;
4390 return VINF_SUCCESS;
4391 }
4392 return VERR_PDM_LUN_NOT_FOUND;
4393}
4394
4395
4396/**
4397 * @copydoc FNPDMDEVRESET
4398 */
4399static DECLCALLBACK(void) pcnetReset(PPDMDEVINS pDevIns)
4400{
4401 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4402 if (pData->fLinkTempDown)
4403 {
4404 pData->cLinkDownReported = 0x10000;
4405 TMTimerStop(pData->pTimerRestore);
4406 pcnetTimerRestore(pDevIns, pData->pTimerRestore);
4407 }
4408 if (pData->pSharedMMIOHC)
4409 pcnetInitSharedMemory(pData);
4410
4411 /** @todo How to flush the queues? */
4412 pcnetHardReset(pData);
4413}
4414
4415
4416/**
4417 * @copydoc FNPDMDEVRELOCATE
4418 */
4419static DECLCALLBACK(void) pcnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4420{
4421 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4422 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
4423 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
4424 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
4425 if (pData->pSharedMMIOHC)
4426 pData->pSharedMMIOGC += offDelta;
4427#ifdef PCNET_NO_POLLING
4428 *(RTHCUINTPTR *)&pData->pfnEMInterpretInstructionGC += offDelta;
4429#else
4430 pData->pTimerPollGC = TMTimerGCPtr(pData->pTimerPollHC);
4431#endif
4432 if (pData->fAm79C973)
4433 pData->pTimerSoftIntGC = TMTimerGCPtr(pData->pTimerSoftIntHC);
4434}
4435
4436
4437/**
4438 * Destruct a device instance.
4439 *
4440 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
4441 * resources can be freed correctly.
4442 *
4443 * @returns VBox status.
4444 * @param pDevIns The device instance data.
4445 */
4446static DECLCALLBACK(int) pcnetDestruct(PPDMDEVINS pDevIns)
4447{
4448 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4449
4450 if (PDMCritSectIsInitialized(&pData->CritSect))
4451 {
4452 /*
4453 * At this point the send thread is suspended and will not enter
4454 * this module again. So, no coordination is needed here and PDM
4455 * will take care of terminating and cleaning up the thread.
4456 */
4457 RTSemEventDestroy(pData->hSendEventSem);
4458 pData->hSendEventSem = NIL_RTSEMEVENT;
4459 PDMR3CritSectDelete(&pData->CritSect);
4460 }
4461#ifdef PCNET_QUEUE_SEND_PACKETS
4462 if (pData->apXmitRingBuffer)
4463 RTMemFree(pData->apXmitRingBuffer[0]);
4464#endif
4465 return VINF_SUCCESS;
4466}
4467
4468
4469/**
4470 * Construct a device instance for a VM.
4471 *
4472 * @returns VBox status.
4473 * @param pDevIns The device instance data.
4474 * If the registration structure is needed, pDevIns->pDevReg points to it.
4475 * @param iInstance Instance number. Use this to figure out which registers and such to use.
4476 * The device number is also found in pDevIns->iInstance, but since it's
4477 * likely to be freqently used PDM passes it as parameter.
4478 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
4479 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
4480 * iInstance it's expected to be used a bit in this function.
4481 */
4482static DECLCALLBACK(int) pcnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
4483{
4484 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4485 PPDMIBASE pBase;
4486 char szTmp[128];
4487 int rc;
4488
4489 /* up to four instances are supported */
4490 Assert((iInstance >= 0) && (iInstance < 4));
4491
4492 Assert(RT_ELEMENTS(pData->aBCR) == BCR_MAX_RAP);
4493 Assert(RT_ELEMENTS(pData->aMII) == MII_MAX_REG);
4494 Assert(sizeof(pData->abSendBuf) == RT_ALIGN_Z(sizeof(pData->abSendBuf), 16));
4495
4496 /*
4497 * Validate configuration.
4498 */
4499 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0CableConnected\0Am79C973\0LineSpeed\0GCEnabled\0R0Enabled\0PrivIfEnabled\0"))
4500 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4501 N_("Invalid configuraton for pcnet device"));
4502
4503 /*
4504 * Read the configuration.
4505 */
4506 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", &pData->MacConfigured, sizeof(pData->MacConfigured));
4507 if (VBOX_FAILURE(rc))
4508 return PDMDEV_SET_ERROR(pDevIns, rc,
4509 N_("Configuration error: Failed to get the \"MAC\" value"));
4510 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pData->fLinkUp);
4511 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4512 pData->fLinkUp = true;
4513 else if (VBOX_FAILURE(rc))
4514 return PDMDEV_SET_ERROR(pDevIns, rc,
4515 N_("Configuration error: Failed to get the \"CableConnected\" value"));
4516
4517 rc = CFGMR3QueryBool(pCfgHandle, "Am79C973", &pData->fAm79C973);
4518 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4519 pData->fAm79C973 = false;
4520 else if (VBOX_FAILURE(rc))
4521 return PDMDEV_SET_ERROR(pDevIns, rc,
4522 N_("Configuration error: Failed to get the \"Am79C973\" value"));
4523
4524 rc = CFGMR3QueryU32(pCfgHandle, "LineSpeed", &pData->u32LinkSpeed);
4525 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4526 pData->u32LinkSpeed = 1000000; /* 1GBit/s (in kbps units)*/
4527 else if (VBOX_FAILURE(rc))
4528 return PDMDEV_SET_ERROR(pDevIns, rc,
4529 N_("Configuration error: Failed to get the \"LineSpeed\" value"));
4530
4531#ifdef PCNET_GC_ENABLED
4532 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
4533 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4534 pData->fGCEnabled = true;
4535 else if (VBOX_FAILURE(rc))
4536 return PDMDEV_SET_ERROR(pDevIns, rc,
4537 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
4538
4539 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
4540 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4541 pData->fR0Enabled = true;
4542 else if (VBOX_FAILURE(rc))
4543 return PDMDEV_SET_ERROR(pDevIns, rc,
4544 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
4545
4546#else /* !PCNET_GC_ENABLED */
4547 pData->fGCEnabled = false;
4548 pData->fR0Enabled = false;
4549#endif /* !PCNET_GC_ENABLED */
4550
4551
4552 /*
4553 * Initialize data (most of it anyway).
4554 */
4555 pData->pDevInsHC = pDevIns;
4556 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
4557 pData->Led.u32Magic = PDMLED_MAGIC;
4558 /* IBase */
4559 pData->IBase.pfnQueryInterface = pcnetQueryInterface;
4560 /* INeworkPort */
4561 pData->INetworkPort.pfnCanReceive = pcnetCanReceive;
4562 pData->INetworkPort.pfnReceive = pcnetReceive;
4563 /* INetworkConfig */
4564 pData->INetworkConfig.pfnGetMac = pcnetGetMac;
4565 pData->INetworkConfig.pfnGetLinkState = pcnetGetLinkState;
4566 pData->INetworkConfig.pfnSetLinkState = pcnetSetLinkState;
4567 /* ILeds */
4568 pData->ILeds.pfnQueryStatusLed = pcnetQueryStatusLed;
4569
4570 /* PCI Device */
4571 PCIDevSetVendorId(&pData->PciDev, 0x1022);
4572 PCIDevSetDeviceId(&pData->PciDev, 0x2000);
4573 pData->PciDev.config[0x04] = 0x07; /* command */
4574 pData->PciDev.config[0x05] = 0x00;
4575 pData->PciDev.config[0x06] = 0x80; /* status */
4576 pData->PciDev.config[0x07] = 0x02;
4577 pData->PciDev.config[0x08] = pData->fAm79C973 ? 0x40 : 0x10; /* revision */
4578 pData->PciDev.config[0x09] = 0x00;
4579 pData->PciDev.config[0x0a] = 0x00; /* ethernet network controller */
4580 pData->PciDev.config[0x0b] = 0x02;
4581 pData->PciDev.config[0x0e] = 0x00; /* header_type */
4582
4583 pData->PciDev.config[0x10] = 0x01; /* IO Base */
4584 pData->PciDev.config[0x11] = 0x00;
4585 pData->PciDev.config[0x12] = 0x00;
4586 pData->PciDev.config[0x13] = 0x00;
4587 pData->PciDev.config[0x14] = 0x00; /* MMIO Base */
4588 pData->PciDev.config[0x15] = 0x00;
4589 pData->PciDev.config[0x16] = 0x00;
4590 pData->PciDev.config[0x17] = 0x00;
4591
4592 /* subsystem and subvendor IDs */
4593 pData->PciDev.config[0x2c] = 0x22; /* subsystem vendor id */
4594 pData->PciDev.config[0x2d] = 0x10;
4595 pData->PciDev.config[0x2e] = 0x00; /* subsystem id */
4596 pData->PciDev.config[0x2f] = 0x20;
4597 pData->PciDev.config[0x3d] = 1; /* interrupt pin 0 */
4598 pData->PciDev.config[0x3e] = 0x06;
4599 pData->PciDev.config[0x3f] = 0xff;
4600
4601 /*
4602 * Register the PCI device, its I/O regions, the timer and the saved state item.
4603 */
4604 rc = PDMDevHlpPCIRegister(pDevIns, &pData->PciDev);
4605 if (VBOX_FAILURE(rc))
4606 return rc;
4607 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, PCNET_IOPORT_SIZE,
4608 PCI_ADDRESS_SPACE_IO, pcnetIOPortMap);
4609 if (VBOX_FAILURE(rc))
4610 return rc;
4611 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, PCNET_PNPMMIO_SIZE,
4612 PCI_ADDRESS_SPACE_MEM, pcnetMMIOMap);
4613 if (VBOX_FAILURE(rc))
4614 return rc;
4615
4616 bool fPrivIfEnabled;
4617 rc = CFGMR3QueryBool(pCfgHandle, "PrivIfEnabled", &fPrivIfEnabled);
4618 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4619 fPrivIfEnabled = true;
4620 else if (VBOX_FAILURE(rc))
4621 return PDMDEV_SET_ERROR(pDevIns, rc,
4622 N_("Configuration error: Failed to get the \"PrivIfEnabled\" value"));
4623
4624 if (fPrivIfEnabled)
4625 {
4626 /*
4627 * Initialize shared memory between host and guest for descriptors and RX buffers. Most guests
4628 * should not care if there is an additional PCI ressource but just in case we made this configurable.
4629 */
4630 rc = PDMDevHlpMMIO2Register(pDevIns, 2, PCNET_GUEST_SHARED_MEMORY_SIZE, 0, (void **)&pData->pSharedMMIOHC, "PCNetShMem");
4631 if (VBOX_FAILURE(rc))
4632 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4633 N_("Failed to allocate %u bytes of memory for the PCNet device"), PCNET_GUEST_SHARED_MEMORY_SIZE);
4634 rc = PDMDevHlpMMHyperMapMMIO2(pDevIns, 2, 0, 8192, "PCNetShMem", &pData->pSharedMMIOGC);
4635 if (VBOX_FAILURE(rc))
4636 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
4637 N_("Failed to map 8192 bytes of memory for the PCNet device into the hyper memory"));
4638 pcnetInitSharedMemory(pData);
4639 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, PCNET_GUEST_SHARED_MEMORY_SIZE,
4640 PCI_ADDRESS_SPACE_MEM, pcnetMMIOSharedMap);
4641 if (VBOX_FAILURE(rc))
4642 return rc;
4643 }
4644
4645#ifdef PCNET_NO_POLLING
4646 rc = PDMR3GetSymbolR0Lazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", &pData->pfnEMInterpretInstructionR0);
4647 if (VBOX_SUCCESS(rc))
4648 {
4649 /*
4650 * Resolve the GC handler.
4651 */
4652 RTGCPTR pfnHandlerGC;
4653 rc = PDMR3GetSymbolGCLazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pData->pfnEMInterpretInstructionGC);
4654 }
4655 if (VBOX_FAILURE(rc))
4656 {
4657 AssertMsgFailed(("PDMR3GetSymbolGCLazy -> %Vrc\n", rc));
4658 return rc;
4659 }
4660#else
4661 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimer,
4662 "PCNet Poll Timer", &pData->pTimerPollHC);
4663 if (VBOX_FAILURE(rc))
4664 {
4665 AssertMsgFailed(("pfnTMTimerCreate pcnetTimer -> %Vrc\n", rc));
4666 return rc;
4667 }
4668#endif
4669 if (pData->fAm79C973)
4670 {
4671 /* Software Interrupt timer */
4672 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerSoftInt,
4673 "PCNet SoftInt Timer", &pData->pTimerSoftIntHC);
4674 if (VBOX_FAILURE(rc))
4675 {
4676 AssertMsgFailed(("pfnTMTimerCreate pcnetTimerSoftInt -> %Vrc\n", rc));
4677 return rc;
4678 }
4679 }
4680 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerRestore,
4681 "PCNet Restore Timer", &pData->pTimerRestore);
4682 if (VBOX_FAILURE(rc))
4683 {
4684 AssertMsgFailed(("pfnTMTimerCreate pcnetTimerRestore -> %Vrc\n", rc));
4685 return rc;
4686 }
4687 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance,
4688 PCNET_SAVEDSTATE_VERSION, sizeof(*pData),
4689 pcnetSavePrep, pcnetSaveExec, NULL,
4690 pcnetLoadPrep, pcnetLoadExec, NULL);
4691 if (VBOX_FAILURE(rc))
4692 return rc;
4693
4694 /*
4695 * Initialize critical section.
4696 * This must of course be done before attaching drivers or anything else which can call us back..
4697 */
4698 char szName[24];
4699 RTStrPrintf(szName, sizeof(szName), "PCNet#%d", iInstance);
4700 rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
4701 if (VBOX_FAILURE(rc))
4702 return rc;
4703
4704 /*
4705 * Create the transmit queue.
4706 */
4707 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4708 pcnetXmitQueueConsumer, true, &pData->pXmitQueueHC);
4709 if (VBOX_FAILURE(rc))
4710 return rc;
4711 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
4712
4713 /*
4714 * Create the RX notifer signaller.
4715 */
4716 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4717 pcnetCanRxQueueConsumer, true, &pData->pCanRxQueueHC);
4718 if (VBOX_FAILURE(rc))
4719 return rc;
4720 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
4721
4722 /*
4723 * Register the info item.
4724 */
4725 RTStrPrintf(szTmp, sizeof(szTmp), "pcnet%d", pDevIns->iInstance);
4726 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "PCNET info.", pcnetInfo);
4727
4728 /*
4729 * Attach status driver (optional).
4730 */
4731 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->IBase, &pBase, "Status Port");
4732 if (VBOX_SUCCESS(rc))
4733 pData->pLedsConnector = (PPDMILEDCONNECTORS)
4734 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
4735 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
4736 {
4737 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
4738 return rc;
4739 }
4740
4741 /*
4742 * Attach driver.
4743 */
4744 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Network Port");
4745 if (VBOX_SUCCESS(rc))
4746 {
4747 if (rc == VINF_NAT_DNS)
4748 {
4749#ifdef RT_OS_LINUX
4750 VMSetRuntimeError(PDMDevHlpGetVM(pDevIns), false, "NoDNSforNAT",
4751 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"));
4752#else
4753 VMSetRuntimeError(PDMDevHlpGetVM(pDevIns), false, "NoDNSforNAT",
4754 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"));
4755#endif
4756 }
4757 pData->pDrv = (PPDMINETWORKCONNECTOR)
4758 pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
4759 if (!pData->pDrv)
4760 {
4761 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
4762 return VERR_PDM_MISSING_INTERFACE_BELOW;
4763 }
4764 }
4765 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4766 Log(("No attached driver!\n"));
4767 else
4768 return rc;
4769
4770 /*
4771 * Reset the device state. (Do after attaching.)
4772 */
4773 pcnetHardReset(pData);
4774
4775 /* Create send queue for the async send thread. */
4776 rc = RTSemEventCreate(&pData->hSendEventSem);
4777 AssertRC(rc);
4778
4779 /* Create asynchronous thread */
4780 rc = PDMDevHlpPDMThreadCreate(pDevIns, &pData->pSendThread, pData, pcnetAsyncSendThread, pcnetAsyncSendThreadWakeUp, 0, RTTHREADTYPE_IO, "PCNET_TX");
4781 AssertRCReturn(rc, rc);
4782
4783 unsigned i;
4784 NOREF(i);
4785
4786#ifdef PCNET_QUEUE_SEND_PACKETS
4787 pData->apXmitRingBuffer[0] = (uint8_t *)RTMemAlloc(PCNET_MAX_XMIT_SLOTS * MAX_FRAME);
4788 for (i = 1; i < PCNET_MAX_XMIT_SLOTS; i++)
4789 pData->apXmitRingBuffer[i] = pData->apXmitRingBuffer[0] + i*MAX_FRAME;
4790#endif
4791
4792#ifdef VBOX_WITH_STATISTICS
4793 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/PCNet%d/MMIO/ReadGC", iInstance);
4794 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/PCNet%d/MMIO/ReadHC", iInstance);
4795 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/PCNet%d/MMIO/WriteGC", iInstance);
4796 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/PCNet%d/MMIO/WriteHC", iInstance);
4797 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM reads", "/Devices/PCNet%d/IO/APROMRead", iInstance);
4798 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM writes", "/Devices/PCNet%d/IO/APROMWrite", iInstance);
4799 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in GC", "/Devices/PCNet%d/IO/ReadGC", iInstance);
4800 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in HC", "/Devices/PCNet%d/IO/ReadHC", iInstance);
4801 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in GC", "/Devices/PCNet%d/IO/WriteGC", iInstance);
4802 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in HC", "/Devices/PCNet%d/IO/WriteHC", iInstance);
4803 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet Timer", "/Devices/PCNet%d/Timer", iInstance);
4804 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet receive", "/Devices/PCNet%d/Receive", iInstance);
4805#endif
4806 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/PCNet%d/ReceiveBytes", iInstance);
4807#ifdef VBOX_WITH_STATISTICS
4808 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet transmit in HC", "/Devices/PCNet%d/Transmit/Total", iInstance);
4809#endif
4810 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/PCNet%d/TransmitBytes", iInstance);
4811#ifdef VBOX_WITH_STATISTICS
4812 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet send transmit in HC","/Devices/PCNet%d/Transmit/Send", iInstance);
4813 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in GC", "/Devices/PCNet%d/TdtePollGC", iInstance);
4814 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in HC", "/Devices/PCNet%d/TdtePollHC", iInstance);
4815 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in GC", "/Devices/PCNet%d/RdtePollGC", iInstance);
4816 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in HC", "/Devices/PCNet%d/RdtePollHC", iInstance);
4817
4818 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTmdStoreGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in GC", "/Devices/PCNet%d/TmdStoreGC", iInstance);
4819 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTmdStoreHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in HC", "/Devices/PCNet%d/TmdStoreHC", iInstance);
4820
4821 for (i = 0; i < ELEMENTS(pData->aStatXmitFlush) - 1; i++)
4822 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d", iInstance, i + 1);
4823 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d+", iInstance, i + 1);
4824
4825 for (i = 0; i < ELEMENTS(pData->aStatXmitChainCounts) - 1; i++)
4826 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d", iInstance, i + 1);
4827 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d+", iInstance, i + 1);
4828
4829 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatXmitSkipCurrent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/Xmit/Skipped", iInstance, i + 1);
4830
4831 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet interrupt checks", "/Devices/PCNet%d/UpdateIRQ", iInstance);
4832 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatPollTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet poll timer", "/Devices/PCNet%d/PollTimer", iInstance);
4833 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMIIReads, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of MII reads", "/Devices/PCNet%d/MIIReads", iInstance);
4834# ifdef PCNET_NO_POLLING
4835 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRCVRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of receive ring writes", "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
4836 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTXRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of transmit ring writes", "/Devices/PCNet%d/Ring/TXWrites", iInstance);
4837 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
4838 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
4839 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
4840 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
4841 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
4842 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
4843 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/HC/Outside", iInstance);
4844 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/R0/Outside", iInstance);
4845 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/GC/Outside", iInstance);
4846# endif /* PCNET_NO_POLLING */
4847#endif
4848
4849 return VINF_SUCCESS;
4850}
4851
4852
4853/**
4854 * The device registration structure.
4855 */
4856const PDMDEVREG g_DevicePCNet =
4857{
4858 /* u32Version */
4859 PDM_DEVREG_VERSION,
4860 /* szDeviceName */
4861 "pcnet",
4862 /* szGCMod */
4863#ifdef PCNET_GC_ENABLED
4864 "VBoxDDGC.gc",
4865 "VBoxDDR0.r0",
4866#else
4867 "",
4868 "",
4869#endif
4870 /* pszDescription */
4871 "AMD PC-Net II Ethernet controller.\n",
4872 /* fFlags */
4873#ifdef PCNET_GC_ENABLED
4874 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
4875#else
4876 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
4877#endif
4878 /* fClass */
4879 PDM_DEVREG_CLASS_NETWORK,
4880 /* cMaxInstances */
4881 4,
4882 /* cbInstance */
4883 sizeof(PCNetState),
4884 /* pfnConstruct */
4885 pcnetConstruct,
4886 /* pfnDestruct */
4887 pcnetDestruct,
4888 /* pfnRelocate */
4889 pcnetRelocate,
4890 /* pfnIOCtl */
4891 NULL,
4892 /* pfnPowerOn */
4893 NULL,
4894 /* pfnReset */
4895 pcnetReset,
4896 /* pfnSuspend */
4897 NULL,
4898 /* pfnResume */
4899 NULL,
4900 /* pfnAttach */
4901 NULL,
4902 /* pfnDetach */
4903 NULL,
4904 /* pfnQueryInterface. */
4905 NULL
4906};
4907
4908#endif /* IN_RING3 */
4909#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4910
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette