VirtualBox

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

Last change on this file since 4071 was 4071, checked in by vboxsync, 18 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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