VirtualBox

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

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

*: whitespace cleanups by scm and two manually picked nits.

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