VirtualBox

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

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

Write LED

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 165.7 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->Led.Asserted.s.fWriting = pData->Led.Actual.s.fWriting = 1;
1873 pData->pDrv->pfnSend(pData->pDrv, pData->SendFrame.pvBuf, pData->SendFrame.cb);
1874 pData->Led.Actual.s.fWriting = 0;
1875 STAM_PROFILE_ADV_STOP(&pData->StatTransmitSend, a);
1876
1877 return PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
1878}
1879
1880
1881/**
1882 * Fails a TMD with a link down error.
1883 */
1884static void pcnetXmitFailTMDLinkDown(PCNetState *pData, TMD *pTmd)
1885{
1886 /* make carrier error - hope this is correct. */
1887 pData->cLinkDownReported++;
1888 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1889 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR */
1890 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1891 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1892 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1893}
1894
1895/**
1896 * Fails a TMD with a generic error.
1897 */
1898static void pcnetXmitFailTMDGeneric(PCNetState *pData, TMD *pTmd)
1899{
1900 /* make carrier error - hope this is correct. */
1901 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1902 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR */
1903 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1904 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1905 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1906}
1907
1908
1909/**
1910 * Transmit a loopback frame.
1911 */
1912DECLINLINE(void) pcnetXmitLoopbackFrame(PCNetState *pData)
1913{
1914 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
1915 if (HOST_IS_OWNER(CSR_CRST(pData)))
1916 pcnetRdtePoll(pData);
1917
1918 Assert(pData->SendFrame.pvBuf);
1919 pcnetReceiveNoSync(pData, (const uint8_t *)pData->SendFrame.pvBuf, pData->SendFrame.cb);
1920 pcnetXmitScrapFrame(pData);
1921 pData->Led.Actual.s.fReading = 0;
1922}
1923
1924/**
1925 * Flushes queued frames.
1926 */
1927DECLINLINE(void) pcnetXmitFlushFrames(PCNetState *pData)
1928{
1929 pcnetXmitQueueConsumer(CTXSUFF(pData->pDevIns), NULL);
1930}
1931
1932#endif /* IN_RING3 */
1933
1934
1935
1936/**
1937 * Try to transmit frames
1938 */
1939static void pcnetTransmit(PCNetState *pData)
1940{
1941 if (RT_UNLIKELY(!CSR_TXON(pData)))
1942 {
1943 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
1944 return;
1945 }
1946
1947 /*
1948 * Check the current transmit descriptors.
1949 */
1950 TMD tmd;
1951 if (!pcnetTdtePoll(pData, &tmd))
1952 return;
1953
1954 /* Update TDMD, TXSTRT and TINT. */
1955 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
1956
1957 /*
1958 * If we're in Ring-3 we should flush the queue now, in GC/R0 we'll queue a flush job.
1959 */
1960#ifdef IN_RING3
1961 pcnetXmitFlushFrames(pData);
1962#else
1963# if 1
1964 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
1965 if (RT_UNLIKELY(pItem))
1966 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
1967# else
1968 if (ASMAtomicIncU32(&pData->cPendingSends) < 16)
1969 {
1970 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
1971 if (RT_UNLIKELY(pItem))
1972 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
1973 }
1974 else
1975 PDMQueueFlush(CTXSUFF(pData->pXmitQueue));
1976# endif
1977#endif
1978}
1979
1980#ifdef IN_RING3
1981
1982/**
1983 * Try to transmit frames
1984 */
1985static int pcnetAsyncTransmit(PCNetState *pData)
1986{
1987 unsigned cFlushIrq = 0;
1988
1989 Assert(PDMCritSectIsOwner(&pData->CritSect));
1990
1991 if (RT_UNLIKELY(!CSR_TXON(pData)))
1992 {
1993 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
1994 return VINF_SUCCESS;
1995 }
1996
1997 /*
1998 * Iterate the transmit descriptors.
1999 */
2000 STAM_PROFILE_ADV_START(&pData->StatTransmit, a);
2001 do
2002 {
2003#ifdef VBOX_WITH_STATISTICS
2004 unsigned cBuffers = 1;
2005#endif
2006 TMD tmd;
2007 if (!pcnetTdtePoll(pData, &tmd))
2008 break;
2009
2010 /* Don't continue sending packets when the link is down. */
2011 if (RT_UNLIKELY( !pcnetIsLinkUp(pData)
2012 && pData->cLinkDownReported > PCNET_MAX_LINKDOWN_REPORTED)
2013 )
2014 break;
2015
2016#ifdef PCNET_DEBUG_TMD
2017 Log2(("#%d TMDLOAD %#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
2018 PRINT_TMD(&tmd);
2019#endif
2020 pcnetXmitScrapFrame(pData);
2021
2022 /*
2023 * The typical case - a complete packet.
2024 * This can be performed with zero copy in Ring-3.
2025 */
2026 if (tmd.tmd1.stp && tmd.tmd1.enp)
2027 {
2028 const unsigned cb = 4096 - tmd.tmd1.bcnt;
2029 Log(("#%d pcnetTransmit: stp&enp: cb=%d xmtrc=%#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, cb, CSR_XMTRC(pData)));
2030
2031 if (RT_LIKELY(pcnetIsLinkUp(pData) || CSR_LOOP(pData)))
2032 {
2033 RTR3PTR pv;
2034
2035 /* From the manual: ``A zero length buffer is acceptable as
2036 * long as it is not the last buffer in a chain (STP = 0 and
2037 * ENP = 1).'' That means that the first buffer might have a
2038 * zero length if it is not the last one in the chain. */
2039 if (RT_LIKELY(cb <= 1536))
2040 {
2041 int rc = PDMDevHlpPhys2HCVirt(pData->pDevInsHC,
2042 PHYSADDR(pData, tmd.tmd0.tbadr), cb, &pv);
2043 if (RT_SUCCESS(rc))
2044 pcnetXmitZeroCopyFrame(pData, pv, cb);
2045 else
2046 {
2047 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2048 }
2049 if (CSR_LOOP(pData))
2050 pcnetXmitLoopbackFrame(pData);
2051 else
2052 {
2053 int rc = pcnetXmitCompleteFrame(pData);
2054 if (VBOX_FAILURE(rc))
2055 return rc; /* can happen during termination */
2056 }
2057 }
2058 else if (cb == 4096)
2059 {
2060 /* The Windows NT4 pcnet driver sometimes marks the first
2061 * unused descriptor as owned by us. Ignore that (by
2062 * passing it back). Do not update the ring counter in this
2063 * case (otherwise that driver becomes even more confused,
2064 * which causes transmit to stall for about 10 seconds).
2065 * This is just a workaround, not a final solution. */
2066 /* r=frank: IMHO this is the correct implementation. The
2067 * manual says: ``If the OWN bit is set and the buffer
2068 * length is 0, the OWN bit will be cleared. In the C-LANCE
2069 * the buffer length of 0 is interpreted as a 4096-byte
2070 * buffer.'' */
2071 LogRel(("PCNET: pcnetAsyncTransmit: illegal 4kb frame -> ignoring\n"));
2072 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2073 break;
2074 }
2075 else
2076 {
2077 /* Signal error, as this violates the Ethernet specs. */
2078 /** @todo check if the correct error is generated. */
2079 LogRel(("PCNET: pcnetAsyncTransmit: illegal 4kb frame -> signalling error\n"));
2080
2081 pcnetXmitFailTMDGeneric(pData, &tmd);
2082 }
2083 }
2084 else
2085 pcnetXmitFailTMDLinkDown(pData, &tmd);
2086
2087 /* Write back the TMD and pass it to the host (clear own bit). */
2088 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2089
2090 /* advance the ring counter register */
2091 if (CSR_XMTRC(pData) < 2)
2092 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2093 else
2094 CSR_XMTRC(pData)--;
2095 }
2096 else if (tmd.tmd1.stp)
2097 {
2098 /*
2099 * Read TMDs until end-of-packet or tdte poll fails (underflow).
2100 */
2101 const unsigned cbMaxFrame = 1536;
2102 bool fDropFrame = false;
2103 unsigned cb = 4096 - tmd.tmd1.bcnt;
2104 pcnetXmitRead1st(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2105 for (;;)
2106 {
2107 /*
2108 * Advance the ring counter register and check the next tmd.
2109 */
2110#ifdef LOG_ENABLED
2111 const uint32_t iStart = CSR_XMTRC(pData);
2112#endif
2113 const uint32_t GCPhysPrevTmd = PHYSADDR(pData, CSR_CXDA(pData));
2114 if (CSR_XMTRC(pData) < 2)
2115 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2116 else
2117 CSR_XMTRC(pData)--;
2118
2119 TMD dummy;
2120 if (!pcnetTdtePoll(pData, &dummy))
2121 {
2122 /*
2123 * Underflow!
2124 */
2125 tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
2126 pData->aCSR[0] |= 0x0200; /* set TINT */
2127 if (!CSR_DXSUFLO(pData)) /* stop on xmit underflow */
2128 pData->aCSR[0] &= ~0x0010; /* clear TXON */
2129 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2130 AssertMsgFailed(("pcnetTransmit: Underflow!!!\n"));
2131 break;
2132 }
2133
2134 /* release & save the previous tmd, pass it to the host */
2135 pcnetTmdStorePassHost(pData, &tmd, GCPhysPrevTmd);
2136
2137 /*
2138 * The next tdm.
2139 */
2140#ifdef VBOX_WITH_STATISTICS
2141 cBuffers++;
2142#endif
2143 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2144 cb = 4096 - tmd.tmd1.bcnt;
2145 if ( pData->SendFrame.cb + cb < cbMaxFrame
2146 && !fDropFrame)
2147 pcnetXmitReadMore(pData, PHYSADDR(pData, tmd.tmd0.tbadr), cb);
2148 else
2149 {
2150 AssertMsg(fDropFrame, ("pcnetTransmit: Frame is too big!!! %d bytes\n",
2151 pData->SendFrame.cb + cb));
2152 fDropFrame = true;
2153 }
2154 if (tmd.tmd1.enp)
2155 {
2156 Log(("#%d pcnetTransmit: stp: cb=%d xmtrc=%#x-%#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2157 pData->SendFrame.cb, iStart, CSR_XMTRC(pData)));
2158 if (pcnetIsLinkUp(pData) && !fDropFrame)
2159 {
2160 int rc = pcnetXmitCompleteFrame(pData);
2161 if (VBOX_FAILURE(rc))
2162 return rc; /* can happen during termination */
2163 }
2164 else if (CSR_LOOP(pData) && !fDropFrame)
2165 pcnetXmitLoopbackFrame(pData);
2166 else
2167 {
2168 if (!fDropFrame)
2169 pcnetXmitFailTMDLinkDown(pData, &tmd);
2170 pcnetXmitScrapFrame(pData);
2171 }
2172
2173 /* Write back the TMD, pass it to the host */
2174 pcnetTmdStorePassHost(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2175
2176 /* advance the ring counter register */
2177 if (CSR_XMTRC(pData) < 2)
2178 CSR_XMTRC(pData) = CSR_XMTRL(pData);
2179 else
2180 CSR_XMTRC(pData)--;
2181 break;
2182 }
2183 }
2184 }
2185 else
2186 {
2187 /*
2188 * We underflowed in a previous transfer, or the driver is giving us shit.
2189 * Simply stop the transmitting for now.
2190 */
2191 /** @todo according to the specs we're supposed to clear the own bit and move on to the next one. */
2192 Log(("#%d pcnetTransmit: guest is giving us shit!\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
2193 break;
2194 }
2195 /* Update TDMD, TXSTRT and TINT. */
2196 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
2197
2198 pData->aCSR[4] |= 0x0004; /* set TXSTRT */
2199 if ( !CSR_TOKINTD(pData) /* Transmit OK Interrupt Disable, no infl. on errors. */
2200 || (CSR_LTINTEN(pData) && tmd.tmd1.ltint)
2201 || tmd.tmd1.err)
2202 {
2203 cFlushIrq++;
2204 pData->aCSR[0] |= 0x0200; /* set TINT */
2205 }
2206
2207 /** @todo should we continue after an error (tmd.tmd1.err) or not? */
2208
2209 STAM_COUNTER_INC(&pData->aStatXmitChainCounts[RT_MIN(cBuffers,
2210 ELEMENTS(pData->aStatXmitChainCounts)) - 1]);
2211 } while (CSR_TXON(pData)); /* transfer on */
2212
2213 if (cFlushIrq)
2214 {
2215 STAM_COUNTER_INC(&pData->aStatXmitFlush[RT_MIN(cFlushIrq, ELEMENTS(pData->aStatXmitFlush)) - 1]);
2216 pcnetUpdateIrq(pData);
2217 }
2218
2219 STAM_PROFILE_ADV_STOP(&pData->StatTransmit, a);
2220
2221 return VINF_SUCCESS;
2222}
2223
2224/**
2225 * Async I/O thread for delayed sending of packets.
2226 */
2227static DECLCALLBACK(int) pcnetAsyncSend(RTTHREAD ThreadSelf, void *pvUser)
2228{
2229 PCNetState *pData = (PCNetState *)pvUser;
2230 RTSEMEVENT hEvent = pData->hSendEventSem;
2231 int rc = VINF_SUCCESS;
2232
2233 while(rc == VINF_SUCCESS)
2234 {
2235 rc = RTSemEventWait(hEvent, RT_INDEFINITE_WAIT);
2236 if (VBOX_FAILURE(rc))
2237 break;
2238
2239 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
2240 AssertReleaseRC(rc);
2241
2242 if (!pData->fSaving)
2243 rc = pcnetAsyncTransmit(pData);
2244
2245 PDMCritSectLeave(&pData->CritSect);
2246 }
2247 return VINF_SUCCESS;
2248}
2249
2250#endif /* IN_RING3 */
2251
2252/**
2253 * Poll for changes in RX and TX descriptor rings.
2254 */
2255static void pcnetPollRxTx(PCNetState *pData)
2256{
2257 if (CSR_RXON(pData))
2258 if (HOST_IS_OWNER(CSR_CRST(pData))) /* Only poll RDTEs if none available */
2259 pcnetRdtePoll(pData);
2260
2261 if (CSR_TDMD(pData) || CSR_TXON(pData) && !CSR_DPOLL(pData))
2262 pcnetTransmit(pData);
2263}
2264
2265/**
2266 * Update the poller timer
2267 * @thread EMT,
2268 */
2269static void pcnetPollTimer(PCNetState *pData)
2270{
2271 STAM_PROFILE_ADV_START(&pData->StatPollTimer, a);
2272
2273#ifdef LOG_ENABLED
2274 TMD dummy;
2275 Log2(("#%d pcnetPollTimer time=%#010x TDMD=%d TXON=%d POLL=%d TDTE=%d TDRA=%#x\n",
2276 PCNETSTATE_2_DEVINS(pData)->iInstance, RTTimeMilliTS(), CSR_TDMD(pData), CSR_TXON(pData),
2277 !CSR_DPOLL(pData), pcnetTdtePoll(pData, &dummy), pData->GCTDRA));
2278 Log2(("#%d pcnetPollTimer: CSR_CXDA=%#x CSR_XMTRL=%d CSR_XMTRC=%d\n",
2279 PCNETSTATE_2_DEVINS(pData)->iInstance, CSR_CXDA(pData), CSR_XMTRL(pData), CSR_XMTRC(pData)));
2280#endif
2281#ifdef PCNET_DEBUG_TMD
2282 if (CSR_CXDA(pData))
2283 {
2284 TMD tmd;
2285 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, CSR_CXDA(pData)));
2286 Log2(("#%d pcnetPollTimer: TMDLOAD %#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
2287 PRINT_TMD(&tmd);
2288 }
2289#endif
2290 if (CSR_TDMD(pData))
2291 pcnetTransmit(pData);
2292
2293 pcnetUpdateIrq(pData);
2294
2295 if (RT_LIKELY(!CSR_STOP(pData) && !CSR_SPND(pData) && !CSR_DPOLL(pData)))
2296 {
2297 /* We ensure that we poll at least every 2ms (500Hz) but not more often than
2298 * 5000 times per second. This way we completely prevent the overhead from
2299 * heavy reprogramming the timer which turned out to be very CPU-intensive.
2300 * The drawback is that csr46 and csr47 are not updated properly anymore
2301 * but so far I have not seen any guest depending on these values. The 2ms
2302 * interval is the default polling interval of the PCNet card (65536/33MHz). */
2303#ifdef PCNET_NO_POLLING
2304 pcnetPollRxTx(pData);
2305#else
2306 uint64_t u64Now = TMTimerGet(pData->CTXSUFF(pTimerPoll));
2307 if (RT_UNLIKELY(u64Now - pData->u64LastPoll > 200000))
2308 {
2309 pData->u64LastPoll = u64Now;
2310 pcnetPollRxTx(pData);
2311 }
2312 if (!TMTimerIsActive(pData->CTXSUFF(pTimerPoll)))
2313 /* Poll timer interval is fixed to 500Hz. Don't stop it. */
2314 TMTimerSet(pData->CTXSUFF(pTimerPoll),
2315 TMTimerGet(pData->CTXSUFF(pTimerPoll)) + 2000000);
2316#endif
2317 }
2318 STAM_PROFILE_ADV_STOP(&pData->StatPollTimer, a);
2319}
2320
2321
2322static int pcnetCSRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t new_value)
2323{
2324 uint16_t val = new_value;
2325 int rc = VINF_SUCCESS;
2326#ifdef PCNET_DEBUG_CSR
2327 Log(("#%d pcnetCSRWriteU16: rap=%d val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2328#endif
2329 switch (u32RAP)
2330 {
2331 case 0:
2332 {
2333 uint16_t csr0 = pData->aCSR[0];
2334 /* Clear any interrupt flags.
2335 * Don't clear an interrupt flag which was not seen by the guest yet. */
2336 csr0 &= ~(val & 0x7f00 & pData->u16CSR0LastSeenByGuest);
2337 csr0 = (csr0 & ~0x0040) | (val & 0x0048);
2338 val = (val & 0x007f) | (csr0 & 0x7f00);
2339
2340 /* Iff STOP, STRT and INIT are set, clear STRT and INIT */
2341 if ((val & 7) == 7)
2342 val &= ~3;
2343
2344#ifndef IN_RING3
2345 if (!(csr0 & 0x0001/*init*/) && (val & 1))
2346 {
2347 Log(("#%d pcnetCSRWriteU16: pcnetInit requested => HC\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
2348 return VINF_IOM_HC_IOPORT_WRITE;
2349 }
2350#endif
2351 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %#06x => %#06x (%#06x)\n",
2352 PCNETSTATE_2_DEVINS(pData)->iInstance,
2353 u32RAP, new_value, csr0, pData->aCSR[0]));
2354 pData->aCSR[0] = csr0;
2355
2356 if (!CSR_STOP(pData) && (val & 4))
2357 pcnetStop(pData);
2358
2359#ifdef IN_RING3
2360 if (!CSR_INIT(pData) && (val & 1))
2361 pcnetInit(pData);
2362#endif
2363
2364 if (!CSR_STRT(pData) && (val & 2))
2365 pcnetStart(pData);
2366
2367 if (CSR_TDMD(pData))
2368 pcnetTransmit(pData);
2369
2370 return rc;
2371 }
2372 case 1: /* IADRL */
2373 case 2: /* IADRH */
2374 case 8: /* LADRF 0..15 */
2375 case 9: /* LADRF 16..31 */
2376 case 10: /* LADRF 32..47 */
2377 case 11: /* LADRF 48..63 */
2378 case 12: /* PADR 0..15 */
2379 case 13: /* PADR 16..31 */
2380 case 14: /* PADR 32..47 */
2381 case 18: /* CRBAL */
2382 case 19: /* CRBAU */
2383 case 20: /* CXBAL */
2384 case 21: /* CXBAU */
2385 case 22: /* NRBAL */
2386 case 23: /* NRBAU */
2387 case 24: /* BADRL */
2388 case 25: /* BADRU */
2389 case 26: /* NRDAL */
2390 case 27: /* NRDAU */
2391 case 28: /* CRDAL */
2392 case 29: /* CRDAU */
2393 case 30: /* BADXL */
2394 case 31: /* BADXU */
2395 case 32: /* NXDAL */
2396 case 33: /* NXDAU */
2397 case 34: /* CXDAL */
2398 case 35: /* CXDAU */
2399 case 36: /* NNRDL */
2400 case 37: /* NNRDU */
2401 case 38: /* NNXDL */
2402 case 39: /* NNXDU */
2403 case 40: /* CRBCL */
2404 case 41: /* CRBCU */
2405 case 42: /* CXBCL */
2406 case 43: /* CXBCU */
2407 case 44: /* NRBCL */
2408 case 45: /* NRBCU */
2409 case 46: /* POLL */
2410 case 47: /* POLLINT */
2411 case 72: /* RCVRC */
2412 case 74: /* XMTRC */
2413 case 76: /* RCVRL */ /** @todo call pcnetUpdateRingHandlers */
2414 /** @todo receive ring length is stored in two's complement! */
2415 case 78: /* XMTRL */ /** @todo call pcnetUpdateRingHandlers */
2416 /** @todo transmit ring length is stored in two's complement! */
2417 case 112: /* MISSC */
2418 if (CSR_STOP(pData) || CSR_SPND(pData))
2419 break;
2420 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %#06x\n",
2421 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2422 return rc;
2423 case 3: /* Interrupt Mask and Deferral Control */
2424 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %#06x\n",
2425 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2426 break;
2427 case 4: /* Test and Features Control */
2428 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %#06x\n",
2429 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2430 pData->aCSR[4] &= ~(val & 0x026a);
2431 val &= ~0x026a;
2432 val |= pData->aCSR[4] & 0x026a;
2433 break;
2434 case 5: /* Extended Control and Interrupt 1 */
2435 LOG_REGISTER(("PCNet#%d: WRITE CSR%d, %#06x\n",
2436 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2437 pData->aCSR[5] &= ~(val & 0x0a90);
2438 val &= ~0x0a90;
2439 val |= pData->aCSR[5] & 0x0a90;
2440 break;
2441 case 15: /* Mode */
2442 if ((pData->aCSR[15] & 0x8000) != (val & 0x8000) && pData->pDrv)
2443 {
2444 Log(("PCNet#%d: promiscuous mode changed to %d\n",
2445 PCNETSTATE_2_DEVINS(pData)->iInstance, !!(val & 0x8000)));
2446#ifndef IN_RING3
2447 return VINF_IOM_HC_IOPORT_WRITE;
2448#else
2449 /* check for promiscuous mode change */
2450 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, !!(val & 0x8000));
2451#endif
2452 }
2453 break;
2454 case 16: /* IADRL */
2455 return pcnetCSRWriteU16(pData, 1, val);
2456 case 17: /* IADRH */
2457 return pcnetCSRWriteU16(pData, 2, val);
2458 case 58: /* Software Style */
2459 LOG_REGISTER(("PCNet#%d: WRITE SW_STYLE, %#06x\n",
2460 PCNETSTATE_2_DEVINS(pData)->iInstance, val));
2461 rc = pcnetBCRWriteU16(pData, BCR_SWS, val);
2462 break;
2463 default:
2464 return rc;
2465 }
2466 pData->aCSR[u32RAP] = val;
2467 return rc;
2468}
2469
2470static uint32_t pcnetCSRReadU16(PCNetState *pData, uint32_t u32RAP)
2471{
2472 uint32_t val;
2473 switch (u32RAP)
2474 {
2475 case 0:
2476 pcnetUpdateIrq(pData);
2477 val = pData->aCSR[0];
2478 val |= (val & 0x7800) ? 0x8000 : 0;
2479 pData->u16CSR0LastSeenByGuest = val;
2480 break;
2481 case 16:
2482 return pcnetCSRReadU16(pData, 1);
2483 case 17:
2484 return pcnetCSRReadU16(pData, 2);
2485 case 58:
2486 return pcnetBCRReadU16(pData, BCR_SWS);
2487 case 88:
2488 val = pData->aCSR[89];
2489 val <<= 16;
2490 val |= pData->aCSR[88];
2491 break;
2492 default:
2493 val = pData->aCSR[u32RAP];
2494 LOG_REGISTER(("PCNet#%d: read CSR%d => %#06x\n",
2495 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2496 }
2497#ifdef PCNET_DEBUG_CSR
2498 Log(("#%d pcnetCSRReadU16: u32RAP=%d val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2499 u32RAP, val));
2500#endif
2501 return val;
2502}
2503
2504static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val)
2505{
2506 int rc = VINF_SUCCESS;
2507 u32RAP &= 0x7f;
2508#ifdef PCNET_DEBUG_BCR
2509 Log2(("#%d pcnetBCRWriteU16: u32RAP=%d val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2510 u32RAP, val));
2511#endif
2512 switch (u32RAP)
2513 {
2514 case BCR_SWS:
2515 if (!(CSR_STOP(pData) || CSR_SPND(pData)))
2516 return rc;
2517 val &= ~0x0300;
2518 switch (val & 0x00ff)
2519 {
2520 default:
2521 Log(("Bad SWSTYLE=%#04x\n", val & 0xff));
2522 // fall through
2523 case 0:
2524 val |= 0x0200; /* 16 bit */
2525 pData->iLog2DescSize = 3;
2526 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
2527 break;
2528 case 1:
2529 val |= 0x0100; /* 32 bit */
2530 pData->iLog2DescSize = 4;
2531 pData->GCUpperPhys = 0;
2532 break;
2533 case 2:
2534 case 3:
2535 val |= 0x0300; /* 32 bit */
2536 pData->iLog2DescSize = 4;
2537 pData->GCUpperPhys = 0;
2538 break;
2539 }
2540 LOG_REGISTER(("PCNet#%d: WRITE SW_STYLE, %#06x\n",
2541 PCNETSTATE_2_DEVINS(pData)->iInstance, val));
2542 Log(("BCR_SWS=%#06x\n", val));
2543 pData->aCSR[58] = val;
2544 /* fall through */
2545 case BCR_LNKST:
2546 case BCR_LED1:
2547 case BCR_LED2:
2548 case BCR_LED3:
2549 case BCR_MC:
2550 case BCR_FDC:
2551 case BCR_BSBC:
2552 case BCR_EECAS:
2553 case BCR_PLAT:
2554 case BCR_MIIADDR:
2555 LOG_REGISTER(("PCNet#%d: WRITE BCR%d, %#06x\n",
2556 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2557 pData->aBCR[u32RAP] = val;
2558 break;
2559
2560 case BCR_MIIMDR:
2561 LOG_REGISTER(("PCNet#%d: WRITE MII%d, %#06x\n",
2562 PCNETSTATE_2_DEVINS(pData)->iInstance, u32RAP, val));
2563 pData->aMII[pData->aBCR[BCR_MIIADDR] & 0x1f] = val;
2564 break;
2565
2566 default:
2567 break;
2568 }
2569 return rc;
2570}
2571
2572static uint32_t pcnetMIIReadU16(PCNetState *pData, uint32_t miiaddr)
2573{
2574 uint32_t val;
2575 STAM_COUNTER_INC(&pData->StatMIIReads);
2576
2577 switch (miiaddr)
2578 {
2579 case 0:
2580 /* MII basic mode control register. */
2581 val = 0x1000; /* Enable auto negotiation. */
2582 break;
2583
2584 case 1:
2585 /* MII basic mode status register. */
2586 if (pData->fLinkUp && !pData->fLinkTempDown)
2587 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2588 | 0x0020 /* Auto-negotiation complete. */
2589 | 0x0008 /* Able to do auto-negotiation. */
2590 | 0x0004 /* Link status. */
2591 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2592 else
2593 {
2594 val = 0x7800 /* Can do 100mbps FD/HD and 10mbps FD/HD. */
2595 | 0x0008 /* Able to do auto-negotiation. */
2596 | 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
2597 pData->cLinkDownReported++;
2598 }
2599 break;
2600
2601 case 2:
2602 /* PHY identifier 1. */
2603 val = 0; /* No name PHY. */
2604 break;
2605
2606 case 3:
2607 /* PHY identifier 2. */
2608 val = 0; /* No name PHY. */
2609 break;
2610
2611 case 4:
2612 /* Advertisement control register. */
2613 val = 0x05e0 /* Try flow control, 100mbps FD/HD and 10mbps FD/HD. */
2614 | 0x0001; /* CSMA selector. */
2615 break;
2616
2617 case 5:
2618 /* Link partner ability register. */
2619 if (pData->fLinkUp && !pData->fLinkTempDown)
2620 val = 0x8000 /* Next page bit. */
2621 | 0x4000 /* Link partner acked us. */
2622 | 0x05e0 /* Can do flow control, 100mbps FD/HD and 10mbps FD/HD. */
2623 | 0x0001; /* Use CSMA selector. */
2624 else
2625 {
2626 val = 0;
2627 pData->cLinkDownReported++;
2628 }
2629 break;
2630
2631 case 6:
2632 /* Auto negotiation expansion register. */
2633 if (pData->fLinkUp && !pData->fLinkTempDown)
2634 val = 0x0008 /* Link partner supports npage. */
2635 | 0x0004 /* Enable npage words. */
2636 | 0x0001; /* Can do N-way auto-negotiation. */
2637 else
2638 {
2639 val = 0;
2640 pData->cLinkDownReported++;
2641 }
2642 break;
2643
2644 default:
2645 val = 0;
2646 break;
2647 }
2648
2649#ifdef PCNET_DEBUG_MII
2650 Log(("#%d pcnet: mii read %d -> %#x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2651 miiaddr, val));
2652#endif
2653 return val;
2654}
2655
2656static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP)
2657{
2658 uint32_t val;
2659 u32RAP &= 0x7f;
2660 switch (u32RAP)
2661 {
2662 case BCR_LNKST:
2663 case BCR_LED1:
2664 case BCR_LED2:
2665 case BCR_LED3:
2666 val = pData->aBCR[u32RAP] & ~0x8000;
2667 /* Clear LNKSTE if we're not connected or if we've just loaded a VM state. */
2668 if (!pData->pDrv || pData->fLinkTempDown || !pData->fLinkUp)
2669 {
2670 if (u32RAP == 4)
2671 pData->cLinkDownReported++;
2672 val &= ~0x40;
2673 }
2674 val |= (val & 0x017f & pData->u32Lnkst) ? 0x8000 : 0;
2675 break;
2676
2677 case BCR_MIIMDR:
2678 if (pData->fAm79C973 && (pData->aBCR[BCR_MIIADDR] >> 5 & 0x1f) == 0)
2679 {
2680 size_t miiaddr = pData->aBCR[BCR_MIIADDR] & 0x1f;
2681 val = pcnetMIIReadU16(pData, miiaddr);
2682 }
2683 else
2684 val = 0xffff;
2685 break;
2686
2687 default:
2688 val = u32RAP < BCR_MAX_RAP ? pData->aBCR[u32RAP] : 0;
2689 break;
2690 }
2691#ifdef PCNET_DEBUG_BCR
2692 Log2(("#%d pcnetBCRReadU16: u32RAP=%d val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2693 u32RAP, val));
2694#endif
2695 return val;
2696}
2697
2698#ifdef IN_RING3 /* move down */
2699static void pcnetHardReset(PCNetState *pData)
2700{
2701 int i;
2702 uint16_t checksum;
2703
2704 /* Initialize the PROM */
2705 Assert(sizeof(pData->MacConfigured) == 6);
2706 memcpy(pData->aPROM, &pData->MacConfigured, sizeof(pData->MacConfigured));
2707 pData->aPROM[ 8] = 0x00;
2708 pData->aPROM[ 9] = 0x11;
2709 pData->aPROM[12] = pData->aPROM[13] = 0x00;
2710 pData->aPROM[14] = pData->aPROM[15] = 0x57;
2711
2712 for (i = 0, checksum = 0; i < 16; i++)
2713 checksum += pData->aPROM[i];
2714 *(uint16_t *)&pData->aPROM[12] = RT_H2LE_U16(checksum);
2715
2716 pData->aBCR[BCR_MSRDA] = 0x0005;
2717 pData->aBCR[BCR_MSWRA] = 0x0005;
2718 pData->aBCR[BCR_MC ] = 0x0002;
2719 pData->aBCR[BCR_LNKST] = 0x00c0;
2720 pData->aBCR[BCR_LED1 ] = 0x0084;
2721 pData->aBCR[BCR_LED2 ] = 0x0088;
2722 pData->aBCR[BCR_LED3 ] = 0x0090;
2723 pData->aBCR[BCR_FDC ] = 0x0000;
2724 pData->aBCR[BCR_BSBC ] = 0x9001;
2725 pData->aBCR[BCR_EECAS] = 0x0002;
2726 pData->aCSR[58 ] = /* CSR58 is an alias for BCR20 */
2727 pData->aBCR[BCR_SWS ] = 0x0200;
2728 pData->iLog2DescSize = 3;
2729 pData->aBCR[BCR_PLAT ] = 0xff06;
2730
2731 pcnetSoftReset(pData);
2732}
2733#endif /* IN_RING3 */
2734
2735static void pcnetAPROMWriteU8(PCNetState *pData, uint32_t addr, uint32_t val)
2736{
2737 addr &= 0x0f;
2738 val &= 0xff;
2739 Log(("#%d pcnetAPROMWriteU8: addr=%#010x val=%#04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2740 addr, val));
2741 /* Check APROMWE bit to enable write access */
2742 if (pcnetBCRReadU16(pData, 2) & 0x80)
2743 pData->aPROM[addr] = val;
2744}
2745
2746static uint32_t pcnetAPROMReadU8(PCNetState *pData, uint32_t addr)
2747{
2748 uint32_t val = pData->aPROM[addr &= 0x0f];
2749 Log(("#%d pcnetAPROMReadU8: addr=%#010x val=%#04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2750 addr, val));
2751 return val;
2752}
2753
2754static int pcnetIoportWriteU16(PCNetState *pData, uint32_t addr, uint32_t val)
2755{
2756 int rc = VINF_SUCCESS;
2757
2758#ifdef PCNET_DEBUG_IO
2759 Log2(("#%d pcnetIoportWriteU16: addr=%#010x val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2760 addr, val));
2761#endif
2762 if (RT_LIKELY(!BCR_DWIO(pData)))
2763 {
2764 switch (addr & 0x0f)
2765 {
2766 case 0x00: /* RDP */
2767 pcnetPollTimer(pData);
2768 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val);
2769 pcnetUpdateIrq(pData);
2770 break;
2771 case 0x02: /* RAP */
2772 pData->u32RAP = val & 0x7f;
2773 break;
2774 case 0x06: /* BDP */
2775 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val);
2776 break;
2777 }
2778 }
2779
2780 return rc;
2781}
2782
2783static uint32_t pcnetIoportReadU16(PCNetState *pData, uint32_t addr, int *pRC)
2784{
2785 uint32_t val = ~0U;
2786
2787 *pRC = VINF_SUCCESS;
2788
2789 if (RT_LIKELY(!BCR_DWIO(pData)))
2790 {
2791 switch (addr & 0x0f)
2792 {
2793 case 0x00: /* RDP */
2794 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
2795 /** Polling is then useless here and possibly expensive. */
2796 if (!CSR_DPOLL(pData))
2797 pcnetPollTimer(pData);
2798
2799 val = pcnetCSRReadU16(pData, pData->u32RAP);
2800 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
2801 goto skip_update_irq;
2802 break;
2803 case 0x02: /* RAP */
2804 val = pData->u32RAP;
2805 goto skip_update_irq;
2806 case 0x04: /* RESET */
2807 pcnetSoftReset(pData);
2808 val = 0;
2809 break;
2810 case 0x06: /* BDP */
2811 val = pcnetBCRReadU16(pData, pData->u32RAP);
2812 break;
2813 }
2814 }
2815 pcnetUpdateIrq(pData);
2816
2817skip_update_irq:
2818#ifdef PCNET_DEBUG_IO
2819 Log2(("#%d pcnetIoportReadU16: addr=%#010x val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2820 addr, val & 0xffff));
2821#endif
2822 return val;
2823}
2824
2825static int pcnetIoportWriteU32(PCNetState *pData, uint32_t addr, uint32_t val)
2826{
2827 int rc = VINF_SUCCESS;
2828
2829#ifdef PCNET_DEBUG_IO
2830 Log2(("#%d pcnetIoportWriteU32: addr=%#010x val=%#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2831 addr, val));
2832#endif
2833 if (RT_LIKELY(BCR_DWIO(pData)))
2834 {
2835 switch (addr & 0x0f)
2836 {
2837 case 0x00: /* RDP */
2838 pcnetPollTimer(pData);
2839 rc = pcnetCSRWriteU16(pData, pData->u32RAP, val & 0xffff);
2840 pcnetUpdateIrq(pData);
2841 break;
2842 case 0x04: /* RAP */
2843 pData->u32RAP = val & 0x7f;
2844 break;
2845 case 0x0c: /* BDP */
2846 rc = pcnetBCRWriteU16(pData, pData->u32RAP, val & 0xffff);
2847 break;
2848 }
2849 }
2850 else if (addr == 0)
2851 {
2852 /* switch device to dword I/O mode */
2853 pcnetBCRWriteU16(pData, BCR_BSBC, pcnetBCRReadU16(pData, BCR_BSBC) | 0x0080);
2854#ifdef PCNET_DEBUG_IO
2855 Log2(("device switched into dword i/o mode\n"));
2856#endif
2857 }
2858
2859 return rc;
2860}
2861
2862static uint32_t pcnetIoportReadU32(PCNetState *pData, uint32_t addr, int *pRC)
2863{
2864 uint32_t val = ~0U;
2865
2866 *pRC = VINF_SUCCESS;
2867
2868 if (RT_LIKELY(BCR_DWIO(pData)))
2869 {
2870 switch (addr & 0x0f)
2871 {
2872 case 0x00: /* RDP */
2873 /** @note if we're not polling, then the guest will tell us when to poll by setting TDMD in CSR0 */
2874 /** Polling is then useless here and possibly expensive. */
2875 if (!CSR_DPOLL(pData))
2876 pcnetPollTimer(pData);
2877
2878 val = pcnetCSRReadU16(pData, pData->u32RAP);
2879 if (pData->u32RAP == 0) // pcnetUpdateIrq() already called by pcnetCSRReadU16()
2880 goto skip_update_irq;
2881 break;
2882 case 0x04: /* RAP */
2883 val = pData->u32RAP;
2884 goto skip_update_irq;
2885 case 0x08: /* RESET */
2886 pcnetSoftReset(pData);
2887 val = 0;
2888 break;
2889 case 0x0c: /* BDP */
2890 val = pcnetBCRReadU16(pData, pData->u32RAP);
2891 break;
2892 }
2893 }
2894 pcnetUpdateIrq(pData);
2895
2896skip_update_irq:
2897#ifdef PCNET_DEBUG_IO
2898 Log2(("#%d pcnetIoportReadU32: addr=%#010x val=%#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2899 addr, val));
2900#endif
2901 return val;
2902}
2903
2904static void pcnetMMIOWriteU8(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2905{
2906#ifdef PCNET_DEBUG_IO
2907 Log2(("#%d pcnetMMIOWriteU8: addr=%#010x val=%#04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2908 addr, val));
2909#endif
2910 if (!(addr & 0x10))
2911 pcnetAPROMWriteU8(pData, addr, val);
2912}
2913
2914static uint32_t pcnetMMIOReadU8(PCNetState *pData, RTGCPHYS addr)
2915{
2916 uint32_t val = ~0U;
2917 if (!(addr & 0x10))
2918 val = pcnetAPROMReadU8(pData, addr);
2919#ifdef PCNET_DEBUG_IO
2920 Log2(("#%d pcnetMMIOReadU8: addr=%#010x val=%#04x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2921 addr, val & 0xff));
2922#endif
2923 return val;
2924}
2925
2926static void pcnetMMIOWriteU16(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2927{
2928#ifdef PCNET_DEBUG_IO
2929 Log2(("#%d pcnetMMIOWriteU16: addr=%#010x val=%#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2930 addr, val));
2931#endif
2932 if (addr & 0x10)
2933 pcnetIoportWriteU16(pData, addr & 0x0f, val);
2934 else
2935 {
2936 pcnetAPROMWriteU8(pData, addr, val );
2937 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
2938 }
2939}
2940
2941static uint32_t pcnetMMIOReadU16(PCNetState *pData, RTGCPHYS addr)
2942{
2943 uint32_t val = ~0U;
2944 int rc;
2945
2946 if (addr & 0x10)
2947 val = pcnetIoportReadU16(pData, addr & 0x0f, &rc);
2948 else
2949 {
2950 val = pcnetAPROMReadU8(pData, addr+1);
2951 val <<= 8;
2952 val |= pcnetAPROMReadU8(pData, addr);
2953 }
2954#ifdef PCNET_DEBUG_IO
2955 Log2(("#%d pcnetMMIOReadU16: addr=%#010x val = %#06x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2956 addr, val & 0xffff));
2957#endif
2958 return val;
2959}
2960
2961static void pcnetMMIOWriteU32(PCNetState *pData, RTGCPHYS addr, uint32_t val)
2962{
2963#ifdef PCNET_DEBUG_IO
2964 Log2(("#%d pcnetMMIOWriteU32: addr=%#010x val=%#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2965 addr, val));
2966#endif
2967 if (addr & 0x10)
2968 pcnetIoportWriteU32(pData, addr & 0x0f, val);
2969 else
2970 {
2971 pcnetAPROMWriteU8(pData, addr, val );
2972 pcnetAPROMWriteU8(pData, addr+1, val >> 8);
2973 pcnetAPROMWriteU8(pData, addr+2, val >> 16);
2974 pcnetAPROMWriteU8(pData, addr+3, val >> 24);
2975 }
2976}
2977
2978static uint32_t pcnetMMIOReadU32(PCNetState *pData, RTGCPHYS addr)
2979{
2980 uint32_t val;
2981 int rc;
2982
2983 if (addr & 0x10)
2984 val = pcnetIoportReadU32(pData, addr & 0x0f, &rc);
2985 else
2986 {
2987 val = pcnetAPROMReadU8(pData, addr+3);
2988 val <<= 8;
2989 val |= pcnetAPROMReadU8(pData, addr+2);
2990 val <<= 8;
2991 val |= pcnetAPROMReadU8(pData, addr+1);
2992 val <<= 8;
2993 val |= pcnetAPROMReadU8(pData, addr );
2994 }
2995#ifdef PCNET_DEBUG_IO
2996 Log2(("#%d pcnetMMIOReadU32: addr=%#010x val=%#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
2997 addr, val));
2998#endif
2999 return val;
3000}
3001
3002
3003/**
3004 * Port I/O Handler for IN operations.
3005 *
3006 * @returns VBox status code.
3007 *
3008 * @param pDevIns The device instance.
3009 * @param pvUser User argument.
3010 * @param Port Port number used for the IN operation.
3011 * @param pu32 Where to store the result.
3012 * @param cb Number of bytes read.
3013 */
3014PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
3015 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3016{
3017 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3018 int rc;
3019 if (cb == 1)
3020 {
3021 STAM_PROFILE_ADV_START(&pData->StatAPROMRead, a);
3022 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3023 if (rc == VINF_SUCCESS)
3024 {
3025 *pu32 = pcnetAPROMReadU8(pData, Port);
3026 PDMCritSectLeave(&pData->CritSect);
3027 }
3028 STAM_PROFILE_ADV_STOP(&pData->StatAPROMRead, a);
3029 }
3030 else
3031 rc = VERR_IOM_IOPORT_UNUSED;
3032 LogFlow(("#%d pcnetIOPortAPromRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n",
3033 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, *pu32, cb, rc));
3034 return rc;
3035}
3036
3037
3038/**
3039 * Port I/O Handler for OUT operations.
3040 *
3041 * @returns VBox status code.
3042 *
3043 * @param pDevIns The device instance.
3044 * @param pvUser User argument.
3045 * @param Port Port number used for the IN operation.
3046 * @param u32 The value to output.
3047 * @param cb The value size in bytes.
3048 */
3049PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
3050 RTIOPORT Port, uint32_t u32, unsigned cb)
3051{
3052 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3053 int rc;
3054
3055 if (cb == 1)
3056 {
3057 STAM_PROFILE_ADV_START(&pData->StatAPROMWrite, a);
3058 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3059 if (rc == VINF_SUCCESS)
3060 {
3061 pcnetAPROMWriteU8(pData, Port, u32);
3062 PDMCritSectLeave(&pData->CritSect);
3063 }
3064 STAM_PROFILE_ADV_STOP(&pData->StatAPROMWrite, a);
3065 }
3066 else
3067 {
3068 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3069 rc = VINF_SUCCESS;
3070 }
3071 LogFlow(("#%d pcnetIOPortAPromWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n",
3072 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, u32, cb, rc));
3073 return rc;
3074}
3075
3076
3077/**
3078 * Port I/O Handler for IN operations.
3079 *
3080 * @returns VBox status code.
3081 *
3082 * @param pDevIns The device instance.
3083 * @param pvUser User argument.
3084 * @param Port Port number used for the IN operation.
3085 * @param pu32 Where to store the result.
3086 * @param cb Number of bytes read.
3087 */
3088PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
3089 RTIOPORT Port, uint32_t *pu32, unsigned cb)
3090{
3091 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3092 int rc = VINF_SUCCESS;
3093
3094 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIORead), a);
3095 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
3096 if (rc == VINF_SUCCESS)
3097 {
3098 switch (cb)
3099 {
3100 case 2: *pu32 = pcnetIoportReadU16(pData, Port, &rc); break;
3101 case 4: *pu32 = pcnetIoportReadU32(pData, Port, &rc); break;
3102 default:
3103 rc = VERR_IOM_IOPORT_UNUSED;
3104 break;
3105 }
3106 PDMCritSectLeave(&pData->CritSect);
3107 }
3108 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIORead), a);
3109 LogFlow(("#%d pcnetIOPortRead: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Vrc\n",
3110 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, *pu32, cb, rc));
3111 return rc;
3112}
3113
3114
3115/**
3116 * Port I/O Handler for OUT operations.
3117 *
3118 * @returns VBox status code.
3119 *
3120 * @param pDevIns The device instance.
3121 * @param pvUser User argument.
3122 * @param Port Port number used for the IN operation.
3123 * @param u32 The value to output.
3124 * @param cb The value size in bytes.
3125 */
3126PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
3127 RTIOPORT Port, uint32_t u32, unsigned cb)
3128{
3129 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3130 int rc = VINF_SUCCESS;
3131
3132 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatIOWrite), a);
3133 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
3134 if (rc == VINF_SUCCESS)
3135 {
3136 switch (cb)
3137 {
3138 case 2: rc = pcnetIoportWriteU16(pData, Port, u32); break;
3139 case 4: rc = pcnetIoportWriteU32(pData, Port, u32); break;
3140 default:
3141 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3142 rc = VERR_INTERNAL_ERROR;
3143 break;
3144 }
3145 PDMCritSectLeave(&pData->CritSect);
3146 }
3147 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatIOWrite), a);
3148 LogFlow(("#%d pcnetIOPortWrite: Port=%RTiop u32=%#RX32 cb=%d rc=%Vrc\n",
3149 PCNETSTATE_2_DEVINS(pData)->iInstance, Port, u32, cb, rc));
3150 return rc;
3151}
3152
3153
3154/**
3155 * Memory mapped I/O Handler for read operations.
3156 *
3157 * @returns VBox status code.
3158 *
3159 * @param pDevIns The device instance.
3160 * @param pvUser User argument.
3161 * @param GCPhysAddr Physical address (in GC) where the read starts.
3162 * @param pv Where to store the result.
3163 * @param cb Number of bytes read.
3164 */
3165PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
3166 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3167{
3168 PCNetState *pData = (PCNetState *)pvUser;
3169 int rc = VINF_SUCCESS;
3170
3171 /*
3172 * We have to check the range, because we're page aligning the MMIO stuff presently.
3173 */
3174 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3175 {
3176 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIORead), a);
3177 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_READ);
3178 if (rc == VINF_SUCCESS)
3179 {
3180 switch (cb)
3181 {
3182 case 1: *(uint8_t *)pv = pcnetMMIOReadU8 (pData, GCPhysAddr); break;
3183 case 2: *(uint16_t *)pv = pcnetMMIOReadU16(pData, GCPhysAddr); break;
3184 case 4: *(uint32_t *)pv = pcnetMMIOReadU32(pData, GCPhysAddr); break;
3185 default:
3186 AssertMsgFailed(("cb=%d\n", cb));
3187 rc = VERR_INTERNAL_ERROR;
3188 break;
3189 }
3190 PDMCritSectLeave(&pData->CritSect);
3191 }
3192 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIORead), a);
3193 }
3194 else
3195 memset(pv, 0, cb);
3196
3197 LogFlow(("#%d pcnetMMIORead: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3198 PCNETSTATE_2_DEVINS(pData)->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3199 return rc;
3200}
3201
3202
3203/**
3204 * Port I/O Handler for write operations.
3205 *
3206 * @returns VBox status code.
3207 *
3208 * @param pDevIns The device instance.
3209 * @param pvUser User argument.
3210 * @param GCPhysAddr Physical address (in GC) where the read starts.
3211 * @param pv Where to fetch the result.
3212 * @param cb Number of bytes to write.
3213 */
3214PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
3215 RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
3216{
3217 PCNetState *pData = (PCNetState *)pvUser;
3218 int rc = VINF_SUCCESS;
3219
3220 /*
3221 * We have to check the range, because we're page aligning the MMIO stuff presently.
3222 */
3223 if (GCPhysAddr - pData->MMIOBase < PCNET_PNPMMIO_SIZE)
3224 {
3225 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatMMIOWrite), a);
3226 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_MMIO_WRITE);
3227 if (rc == VINF_SUCCESS)
3228 {
3229 switch (cb)
3230 {
3231 case 1: pcnetMMIOWriteU8 (pData, GCPhysAddr, *(uint8_t *)pv); break;
3232 case 2: pcnetMMIOWriteU16(pData, GCPhysAddr, *(uint16_t *)pv); break;
3233 case 4: pcnetMMIOWriteU32(pData, GCPhysAddr, *(uint32_t *)pv); break;
3234 default:
3235 AssertMsgFailed(("cb=%d\n", cb));
3236 rc = VERR_INTERNAL_ERROR;
3237 break;
3238 }
3239 PDMCritSectLeave(&pData->CritSect);
3240 }
3241 // else rc == VINF_IOM_HC_MMIO_WRITE => handle in ring3
3242
3243 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatMMIOWrite), a);
3244 }
3245 LogFlow(("#%d pcnetMMIOWrite: pvUser=%p:{%.*Rhxs} cb=%d GCPhysAddr=%RGp rc=%Vrc\n",
3246 PCNETSTATE_2_DEVINS(pData)->iInstance, pv, cb, pv, cb, GCPhysAddr, rc));
3247 return rc;
3248}
3249
3250
3251#ifdef IN_RING3
3252/**
3253 * Device timer callback function.
3254 *
3255 * @param pDevIns Device instance of the device which registered the timer.
3256 * @param pTimer The timer handle.
3257 * @thread EMT
3258 */
3259static DECLCALLBACK(void) pcnetTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3260{
3261 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3262 int rc;
3263
3264 STAM_PROFILE_ADV_START(&pData->StatTimer, a);
3265 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3266 AssertReleaseRC(rc);
3267
3268 pcnetPollTimer(pData);
3269
3270 PDMCritSectLeave(&pData->CritSect);
3271 STAM_PROFILE_ADV_STOP(&pData->StatTimer, a);
3272}
3273
3274
3275/**
3276 * Restore timer callback.
3277 *
3278 * This is only called when've restored a saved state and temporarily
3279 * disconnected the network link to inform the guest that network connections
3280 * should be considered lost.
3281 *
3282 * @param pDevIns Device instance of the device which registered the timer.
3283 * @param pTimer The timer handle.
3284 */
3285static DECLCALLBACK(void) pcnetTimerRestore(PPDMDEVINS pDevIns, PTMTIMER pTimer)
3286{
3287 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3288 int rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3289 AssertReleaseRC(rc);
3290
3291 rc = VERR_GENERAL_FAILURE;
3292 if (pData->cLinkDownReported <= PCNET_MAX_LINKDOWN_REPORTED)
3293 rc = TMTimerSetMillies(pData->pTimerRestore, 1500);
3294 if (VBOX_FAILURE(rc))
3295 {
3296 pData->fLinkTempDown = false;
3297 if (pData->fLinkUp)
3298 {
3299 LogRel(("PCNet#%d: The link is back up again after the restore.\n",
3300 pDevIns->iInstance));
3301 Log(("#%d pcnetTimerRestore: Clearing ERR and CERR after load. cLinkDownReported=%d\n",
3302 pDevIns->iInstance, pData->cLinkDownReported));
3303 pData->aCSR[0] &= ~(BIT(15) | BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3304 pData->Led.Actual.s.fError = 0;
3305 }
3306 }
3307 else
3308 Log(("#%d pcnetTimerRestore: cLinkDownReported=%d, wait another 1500ms...\n",
3309 pDevIns->iInstance, pData->cLinkDownReported));
3310
3311 PDMCritSectLeave(&pData->CritSect);
3312}
3313
3314
3315/**
3316 * Callback function for mapping an PCI I/O region.
3317 *
3318 * @return VBox status code.
3319 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3320 * @param iRegion The region number.
3321 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3322 * I/O port, else it's a physical address.
3323 * This address is *NOT* relative to pci_mem_base like earlier!
3324 * @param cb Region size.
3325 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3326 */
3327static DECLCALLBACK(int) pcnetIOPortMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3328 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3329{
3330 int rc;
3331 PPDMDEVINS pDevIns = pPciDev->pDevIns;
3332 RTIOPORT Port = (RTIOPORT)GCPhysAddress;
3333 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3334
3335 Assert(enmType == PCI_ADDRESS_SPACE_IO);
3336 Assert(cb >= 0x20);
3337
3338 rc = PDMDevHlpIOPortRegister(pDevIns, Port, 0x10, 0, pcnetIOPortAPromWrite,
3339 pcnetIOPortAPromRead, NULL, NULL, "PCNet ARPOM");
3340 if (VBOX_FAILURE(rc))
3341 return rc;
3342 rc = PDMDevHlpIOPortRegister(pDevIns, Port + 0x10, 0x10, 0, pcnetIOPortWrite,
3343 pcnetIOPortRead, NULL, NULL, "PCNet");
3344 if (VBOX_FAILURE(rc))
3345 return rc;
3346
3347 if (pData->fGCEnabled)
3348 {
3349 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3350 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3351 if (VBOX_FAILURE(rc))
3352 return rc;
3353 rc = PDMDevHlpIOPortRegisterGC(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3354 "pcnetIOPortRead", NULL, NULL, "PCNet");
3355 if (VBOX_FAILURE(rc))
3356 return rc;
3357 }
3358 if (pData->fR0Enabled)
3359 {
3360 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port, 0x10, 0, "pcnetIOPortAPromWrite",
3361 "pcnetIOPortAPromRead", NULL, NULL, "PCNet aprom");
3362 if (VBOX_FAILURE(rc))
3363 return rc;
3364 rc = PDMDevHlpIOPortRegisterR0(pDevIns, Port + 0x10, 0x10, 0, "pcnetIOPortWrite",
3365 "pcnetIOPortRead", NULL, NULL, "PCNet");
3366 if (VBOX_FAILURE(rc))
3367 return rc;
3368 }
3369
3370 pData->IOPortBase = Port;
3371 return VINF_SUCCESS;
3372}
3373
3374
3375/**
3376 * Callback function for mapping the MMIO region.
3377 *
3378 * @return VBox status code.
3379 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
3380 * @param iRegion The region number.
3381 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
3382 * I/O port, else it's a physical address.
3383 * This address is *NOT* relative to pci_mem_base like earlier!
3384 * @param cb Region size.
3385 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
3386 */
3387static DECLCALLBACK(int) pcnetMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion,
3388 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
3389{
3390 PCNetState *pData = PCIDEV_2_PCNETSTATE(pPciDev);
3391 int rc;
3392
3393 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
3394 Assert(cb >= PCNET_PNPMMIO_SIZE);
3395
3396 /* We use the assigned size here, because we currently only support page aligned MMIO ranges. */
3397 rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, pData,
3398 pcnetMMIOWrite, pcnetMMIORead, NULL, "PCNet");
3399 if (VBOX_FAILURE(rc))
3400 return rc;
3401 pData->MMIOBase = GCPhysAddress;
3402 return rc;
3403}
3404
3405
3406/**
3407 * PCNET status info callback.
3408 *
3409 * @param pDevIns The device instance.
3410 * @param pHlp The output helpers.
3411 * @param pszArgs The arguments.
3412 */
3413static DECLCALLBACK(void) pcnetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3414{
3415 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3416 bool fRcvRing = false;
3417 bool fXmtRing = false;
3418
3419 /*
3420 * Parse args.
3421 */
3422 if (pszArgs)
3423 {
3424 fRcvRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "rcv");
3425 fXmtRing = strstr(pszArgs, "verbose") || strstr(pszArgs, "xmt");
3426 }
3427
3428 /*
3429 * Show info.
3430 */
3431 pHlp->pfnPrintf(pHlp,
3432 "pcnet #%d: port=%RTiop mmio=%RGp mac-cfg=%.*Rhxs %s\n",
3433 pDevIns->iInstance,
3434 pData->IOPortBase, pData->MMIOBase, sizeof(pData->MacConfigured), &pData->MacConfigured,
3435 pData->fAm79C973 ? "Am79C973" : "Am79C970A", pData->fGCEnabled ? " GC" : "", pData->fR0Enabled ? " R0" : "");
3436
3437 PDMCritSectEnter(&pData->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
3438
3439 pHlp->pfnPrintf(pHlp,
3440 "CSR0=%#06x:\n",
3441 pData->aCSR[0]);
3442
3443 pHlp->pfnPrintf(pHlp,
3444 "CSR1=%#06x:\n",
3445 pData->aCSR[1]);
3446
3447 pHlp->pfnPrintf(pHlp,
3448 "CSR2=%#06x:\n",
3449 pData->aCSR[2]);
3450
3451 pHlp->pfnPrintf(pHlp,
3452 "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",
3453 pData->aCSR[3],
3454 !!(pData->aCSR[3] & BIT(2)), !!(pData->aCSR[3] & BIT(3)), !!(pData->aCSR[3] & BIT(4)), CSR_LAPPEN(pData),
3455 CSR_DXSUFLO(pData), !!(pData->aCSR[3] & BIT(8)), !!(pData->aCSR[3] & BIT(9)), !!(pData->aCSR[3] & BIT(10)),
3456 !!(pData->aCSR[3] & BIT(11)), !!(pData->aCSR[3] & BIT(12)), !!(pData->aCSR[3] & BIT(14)));
3457
3458 pHlp->pfnPrintf(pHlp,
3459 "CSR4=%#06x: JABM=%d JAB=%d TXSTRM=%d TXSTRT=%d RCVCOOM=%d RCVCCO=%d UINT=%d UINTCMD=%d\n"
3460 " MFCOM=%d MFCO=%d ASTRP_RCV=%d APAD_XMT=%d DPOLL=%d TIMER=%d EMAPLUS=%d EN124=%d\n",
3461 pData->aCSR[4],
3462 !!(pData->aCSR[4] & BIT( 0)), !!(pData->aCSR[4] & BIT( 1)), !!(pData->aCSR[4] & BIT( 2)), !!(pData->aCSR[4] & BIT( 3)),
3463 !!(pData->aCSR[4] & BIT( 4)), !!(pData->aCSR[4] & BIT( 5)), !!(pData->aCSR[4] & BIT( 6)), !!(pData->aCSR[4] & BIT( 7)),
3464 !!(pData->aCSR[4] & BIT( 8)), !!(pData->aCSR[4] & BIT( 9)), !!(pData->aCSR[4] & BIT(10)), !!(pData->aCSR[4] & BIT(11)),
3465 !!(pData->aCSR[4] & BIT(12)), !!(pData->aCSR[4] & BIT(13)), !!(pData->aCSR[4] & BIT(14)), !!(pData->aCSR[4] & BIT(15)));
3466
3467 pHlp->pfnPrintf(pHlp,
3468 "CSR5=%#06x:\n",
3469 pData->aCSR[5]);
3470
3471 pHlp->pfnPrintf(pHlp,
3472 "CSR6=%#06x: RLEN=%#x* TLEN=%#x* [* encoded]\n",
3473 pData->aCSR[6],
3474 (pData->aCSR[6] >> 8) & 0xf, (pData->aCSR[6] >> 12) & 0xf);
3475
3476 pHlp->pfnPrintf(pHlp,
3477 "CSR8..11=%#06x,%#06x,%#06x,%#06x: LADRF=%#018llx\n",
3478 pData->aCSR[8], pData->aCSR[9], pData->aCSR[10], pData->aCSR[11],
3479 (uint64_t)(pData->aCSR[ 8] & 0xffff)
3480 | (uint64_t)(pData->aCSR[ 9] & 0xffff) << 16
3481 | (uint64_t)(pData->aCSR[10] & 0xffff) << 32
3482 | (uint64_t)(pData->aCSR[11] & 0xffff) << 48);
3483
3484 pHlp->pfnPrintf(pHlp,
3485 "CSR12..14=%#06x,%#06x,%#06x: PADR=%02x:%02x:%02x:%02x:%02x:%02x (Current MAC Address)\n",
3486 pData->aCSR[12], pData->aCSR[13], pData->aCSR[14],
3487 pData->aCSR[12] & 0xff,
3488 (pData->aCSR[12] >> 8) & 0xff,
3489 pData->aCSR[13] & 0xff,
3490 (pData->aCSR[13] >> 8) & 0xff,
3491 pData->aCSR[14] & 0xff,
3492 (pData->aCSR[14] >> 8) & 0xff);
3493
3494 pHlp->pfnPrintf(pHlp,
3495 "CSR15=%#06x: DXR=%d DTX=%d LOOP=%d DXMTFCS=%d FCOLL=%d DRTY=%d INTL=%d PORTSEL=%d LTR=%d\n"
3496 " MENDECL=%d DAPC=%d DLNKTST=%d DRCVPV=%d DRCVBC=%d PROM=%d\n",
3497 pData->aCSR[15],
3498 !!(pData->aCSR[15] & BIT( 0)), !!(pData->aCSR[15] & BIT( 1)), !!(pData->aCSR[15] & BIT( 2)), !!(pData->aCSR[15] & BIT( 3)),
3499 !!(pData->aCSR[15] & BIT( 4)), !!(pData->aCSR[15] & BIT( 5)), !!(pData->aCSR[15] & BIT( 6)), (pData->aCSR[15] >> 7) & 3,
3500 !!(pData->aCSR[15] & BIT( 9)), !!(pData->aCSR[15] & BIT(10)), !!(pData->aCSR[15] & BIT(11)),
3501 !!(pData->aCSR[15] & BIT(12)), !!(pData->aCSR[15] & BIT(13)), !!(pData->aCSR[15] & BIT(14)), !!(pData->aCSR[15] & BIT(15)));
3502
3503 pHlp->pfnPrintf(pHlp,
3504 "CSR46=%#06x: POLL=%#06x (Poll Time Counter)\n",
3505 pData->aCSR[46], pData->aCSR[46] & 0xffff);
3506
3507 pHlp->pfnPrintf(pHlp,
3508 "CSR47=%#06x: POLLINT=%#06x (Poll Time Interval)\n",
3509 pData->aCSR[47], pData->aCSR[47] & 0xffff);
3510
3511 pHlp->pfnPrintf(pHlp,
3512 "CSR58=%#06x: SWSTYLE=%d %s SSIZE32=%d CSRPCNET=%d APERRENT=%d\n",
3513 pData->aCSR[58],
3514 pData->aCSR[58] & 0x7f,
3515 (pData->aCSR[58] & 0x7f) == 0 ? "C-LANCE / PCnet-ISA"
3516 : (pData->aCSR[58] & 0x7f) == 1 ? "ILACC"
3517 : (pData->aCSR[58] & 0x7f) == 2 ? "PCNet-PCI II"
3518 : (pData->aCSR[58] & 0x7f) == 3 ? "PCNet-PCI II controller"
3519 : "!!reserved!!",
3520 !!(pData->aCSR[58] & BIT(8)), !!(pData->aCSR[58] & BIT(9)), !!(pData->aCSR[58] & BIT(10)));
3521
3522 pHlp->pfnPrintf(pHlp,
3523 "CSR112=%04RX32: MFC=%04x (Missed receive Frame Count)\n",
3524 pData->aCSR[112], pData->aCSR[112] & 0xffff);
3525
3526 pHlp->pfnPrintf(pHlp,
3527 "CSR122=%04RX32: RCVALGN=%04x (Receive Frame Align)\n",
3528 pData->aCSR[122], !!(pData->aCSR[122] & BIT(0)));
3529
3530 pHlp->pfnPrintf(pHlp,
3531 "CSR124=%04RX32: RPA=%04x (Runt Packet Accept)\n",
3532 pData->aCSR[122], !!(pData->aCSR[122] & BIT(3)));
3533
3534
3535 /*
3536 * Dump the receive ring.
3537 */
3538 pHlp->pfnPrintf(pHlp,
3539 "RCVRL=%04x RCVRC=%04x GCRDRA=%RX32 \n"
3540 "CRDA=%08RX32 CRBA=%08RX32 CRBC=%03x CRST=%04x\n"
3541 "NRDA=%08RX32 NRBA=%08RX32 NRBC=%03x NRST=%04x\n"
3542 "NNRDA=%08RX32\n"
3543 ,
3544 CSR_RCVRL(pData), CSR_RCVRC(pData), pData->GCRDRA,
3545 CSR_CRDA(pData), CSR_CRBA(pData), CSR_CRBC(pData), CSR_CRST(pData),
3546 CSR_NRDA(pData), CSR_NRBA(pData), CSR_NRBC(pData), CSR_NRST(pData),
3547 CSR_NNRD(pData));
3548 if (fRcvRing)
3549 {
3550 const unsigned cb = 1 << pData->iLog2DescSize;
3551 RTGCPHYS GCPhys = pData->GCRDRA;
3552 unsigned i = CSR_RCVRL(pData);
3553 while (i-- > 0)
3554 {
3555 RMD rmd;
3556 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys));
3557 pHlp->pfnPrintf(pHlp,
3558 "%04x %RGp:%c%c RBADR=%08RX32 BCNT=%03x MCNT=%03x "
3559 "OWN=%d ERR=%d FRAM=%d OFLO=%d CRC=%d BUFF=%d STP=%d ENP=%d BPE=%d "
3560 "PAM=%d LAFM=%d BAM=%d RCC=%02x RPC=%02x ONES=%#x ZEROS=%d\n",
3561 i, GCPhys, i + 1 == CSR_RCVRC(pData) ? '*' : ' ', GCPhys == CSR_CRDA(pData) ? '*' : ' ',
3562 rmd.rmd0.rbadr, 4096 - rmd.rmd1.bcnt, rmd.rmd2.mcnt,
3563 rmd.rmd1.own, rmd.rmd1.err, rmd.rmd1.fram, rmd.rmd1.oflo, rmd.rmd1.crc, rmd.rmd1.buff,
3564 rmd.rmd1.stp, rmd.rmd1.enp, rmd.rmd1.bpe,
3565 rmd.rmd1.pam, rmd.rmd1.lafm, rmd.rmd1.bam, rmd.rmd2.rcc, rmd.rmd2.rpc,
3566 rmd.rmd1.ones, rmd.rmd2.zeros);
3567
3568 GCPhys += cb;
3569 }
3570 }
3571
3572 /*
3573 * Dump the transmit ring.
3574 */
3575 pHlp->pfnPrintf(pHlp,
3576 "XMTRL=%04x XMTRC=%04x GCTDRA=%08RX32 BADX=%08RX32\n"
3577 "PXDA=%08RX32 PXBC=%03x PXST=%04x\n"
3578 "CXDA=%08RX32 CXBA=%08RX32 CXBC=%03x CXST=%04x\n"
3579 "NXDA=%08RX32 NXBA=%08RX32 NXBC=%03x NXST=%04x\n"
3580 "NNXDA=%08RX32\n"
3581 ,
3582 CSR_XMTRL(pData), CSR_XMTRC(pData),
3583 pData->GCTDRA, CSR_BADX(pData),
3584 CSR_PXDA(pData), CSR_PXBC(pData), CSR_PXST(pData),
3585 CSR_CXDA(pData), CSR_CXBA(pData), CSR_CXBC(pData), CSR_CXST(pData),
3586 CSR_NXDA(pData), CSR_NXBA(pData), CSR_NXBC(pData), CSR_NXST(pData),
3587 CSR_NNXD(pData));
3588 if (fXmtRing)
3589 {
3590 const unsigned cb = 1 << pData->iLog2DescSize;
3591 RTGCPHYS GCPhys = pData->GCTDRA;
3592 unsigned i = CSR_RCVRL(pData);
3593 while (i-- > 0)
3594 {
3595 TMD tmd;
3596 pcnetTmdLoad(pData, &tmd, PHYSADDR(pData, GCPhys));
3597 pHlp->pfnPrintf(pHlp,
3598 "%04x %RGp:%c%c TBADR=%08RX32 BCNT=%03x OWN=%d "
3599 "ERR=%d NOFCS=%d LTINT=%d ONE=%d DEF=%d STP=%d ENP=%d BPE=%d "
3600 "BUFF=%d UFLO=%d EXDEF=%d LCOL=%d LCAR=%d RTRY=%d TDR=%03x TRC=%#x ONES=%#x\n"
3601 ,
3602 i, GCPhys, i + 1 == CSR_XMTRC(pData) ? '*' : ' ', GCPhys == CSR_CXDA(pData) ? '*' : ' ',
3603 tmd.tmd0.tbadr, 4096 - tmd.tmd1.bcnt,
3604 tmd.tmd2.tdr,
3605 tmd.tmd2.trc,
3606 tmd.tmd1.own,
3607 tmd.tmd1.err,
3608 tmd.tmd1.nofcs,
3609 tmd.tmd1.ltint,
3610 tmd.tmd1.one,
3611 tmd.tmd1.def,
3612 tmd.tmd1.stp,
3613 tmd.tmd1.enp,
3614 tmd.tmd1.bpe,
3615 tmd.tmd2.buff,
3616 tmd.tmd2.uflo,
3617 tmd.tmd2.exdef,
3618 tmd.tmd2.lcol,
3619 tmd.tmd2.lcar,
3620 tmd.tmd2.rtry,
3621 tmd.tmd2.tdr,
3622 tmd.tmd2.trc,
3623 tmd.tmd1.ones);
3624
3625 GCPhys += cb;
3626 }
3627 }
3628
3629 PDMCritSectLeave(&pData->CritSect);
3630}
3631
3632
3633/**
3634 * Prepares for state saving.
3635 * We must stop the RX process to prevent altering of the main memory after saving.
3636 *
3637 * @returns VBox status code.
3638 * @param pDevIns The device instance.
3639 * @param pSSMHandle The handle to save the state to.
3640 */
3641static DECLCALLBACK(int) pcnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
3642{
3643 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3644
3645 PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3646
3647 pData->fSaving = true;
3648 /* From now on drop all received packets to prevent altering of main memory after
3649 * pgmR3Save() was called but before the RX thread is terminated */
3650
3651 PDMCritSectLeave(&pData->CritSect);
3652 return VINF_SUCCESS;
3653}
3654
3655
3656/**
3657 * Saves a state of the PC-Net II device.
3658 *
3659 * @returns VBox status code.
3660 * @param pDevIns The device instance.
3661 * @param pSSMHandle The handle to save the state to.
3662 */
3663static DECLCALLBACK(int) pcnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
3664{
3665 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3666
3667 SSMR3PutBool(pSSMHandle, pData->fLinkUp);
3668 SSMR3PutU32(pSSMHandle, pData->u32RAP);
3669 SSMR3PutS32(pSSMHandle, pData->iISR);
3670 SSMR3PutU32(pSSMHandle, pData->u32Lnkst);
3671 SSMR3PutGCPhys(pSSMHandle, pData->GCRDRA);
3672 SSMR3PutGCPhys(pSSMHandle, pData->GCTDRA);
3673 SSMR3PutMem(pSSMHandle, pData->aPROM, sizeof(pData->aPROM));
3674 SSMR3PutMem(pSSMHandle, pData->aCSR, sizeof(pData->aCSR));
3675 SSMR3PutMem(pSSMHandle, pData->aBCR, sizeof(pData->aBCR));
3676 SSMR3PutMem(pSSMHandle, pData->aMII, sizeof(pData->aMII));
3677 SSMR3PutU16(pSSMHandle, pData->u16CSR0LastSeenByGuest);
3678 SSMR3PutU64(pSSMHandle, pData->u64LastPoll);
3679 SSMR3PutMem(pSSMHandle, &pData->MacConfigured, sizeof(pData->MacConfigured));
3680 SSMR3PutBool(pSSMHandle, pData->fAm79C973);
3681#ifdef PCNET_NO_POLLING
3682 return VINF_SUCCESS;
3683#else
3684 return TMR3TimerSave(pData->CTXSUFF(pTimerPoll), pSSMHandle);
3685#endif
3686}
3687
3688
3689/**
3690 * Loads a saved PC-Net II device state.
3691 *
3692 * @returns VBox status code.
3693 * @param pDevIns The device instance.
3694 * @param pSSMHandle The handle to the saved state.
3695 * @param u32Version The data unit version number.
3696 */
3697static DECLCALLBACK(int) pcnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
3698{
3699 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3700 PDMMAC Mac;
3701 if (u32Version != PCNET_SAVEDSTATE_VERSION)
3702 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3703
3704 /* restore data */
3705 SSMR3GetBool(pSSMHandle, &pData->fLinkUp);
3706 SSMR3GetU32(pSSMHandle, &pData->u32RAP);
3707 SSMR3GetS32(pSSMHandle, &pData->iISR);
3708 SSMR3GetU32(pSSMHandle, &pData->u32Lnkst);
3709 SSMR3GetGCPhys(pSSMHandle, &pData->GCRDRA);
3710 SSMR3GetGCPhys(pSSMHandle, &pData->GCTDRA);
3711 SSMR3GetMem(pSSMHandle, &pData->aPROM, sizeof(pData->aPROM));
3712 SSMR3GetMem(pSSMHandle, &pData->aCSR, sizeof(pData->aCSR));
3713 SSMR3GetMem(pSSMHandle, &pData->aBCR, sizeof(pData->aBCR));
3714 SSMR3GetMem(pSSMHandle, &pData->aMII, sizeof(pData->aMII));
3715 SSMR3GetU16(pSSMHandle, &pData->u16CSR0LastSeenByGuest);
3716 SSMR3GetU64(pSSMHandle, &pData->u64LastPoll);
3717 SSMR3GetMem(pSSMHandle, &Mac, sizeof(Mac));
3718 Assert(!memcmp(&Mac, &pData->MacConfigured, sizeof(Mac)));
3719 SSMR3GetBool(pSSMHandle, &pData->fAm79C973);
3720#ifndef PCNET_NO_POLLING
3721 TMR3TimerLoad(pData->CTXSUFF(pTimerPoll), pSSMHandle);
3722#endif
3723
3724 pData->iLog2DescSize = BCR_SWSTYLE(pData)
3725 ? 4
3726 : 3;
3727 pData->GCUpperPhys = BCR_SSIZE32(pData)
3728 ? 0
3729 : (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
3730
3731 /* update promiscuous mode. */
3732 if (pData->pDrv)
3733 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
3734
3735#ifdef PCNET_NO_POLLING
3736 /* Enable physical monitoring again (!) */
3737 pcnetUpdateRingHandlers(pData);
3738#endif
3739 /* Indicate link down to the guest OS that all network connections have been lost. */
3740 if (pData->fLinkUp)
3741 {
3742 pData->fLinkTempDown = true;
3743 pData->cLinkDownReported = 0;
3744 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR (this is probably wrong) */
3745 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
3746 return TMTimerSetMillies(pData->pTimerRestore, 5000);
3747 }
3748 return VINF_SUCCESS;
3749}
3750
3751
3752/**
3753 * Queries an interface to the driver.
3754 *
3755 * @returns Pointer to interface.
3756 * @returns NULL if the interface was not supported by the driver.
3757 * @param pInterface Pointer to this interface structure.
3758 * @param enmInterface The requested interface identification.
3759 * @thread Any thread.
3760 */
3761static DECLCALLBACK(void *) pcnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
3762{
3763 PCNetState *pData = (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, IBase));
3764 Assert(&pData->IBase == pInterface);
3765 switch (enmInterface)
3766 {
3767 case PDMINTERFACE_BASE:
3768 return &pData->IBase;
3769 case PDMINTERFACE_NETWORK_PORT:
3770 return &pData->INetworkPort;
3771 case PDMINTERFACE_NETWORK_CONFIG:
3772 return &pData->INetworkConfig;
3773 case PDMINTERFACE_LED_PORTS:
3774 return &pData->ILeds;
3775 default:
3776 return NULL;
3777 }
3778}
3779
3780/** Converts a pointer to PCNetState::INetworkPort to a PCNetState pointer. */
3781#define INETWORKPORT_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkPort)) )
3782
3783
3784/**
3785 * Check if the device/driver can receive data now.
3786 * This must be called before the pfnRecieve() method is called.
3787 *
3788 * @returns Number of bytes the driver can receive.
3789 * @param pInterface Pointer to the interface structure containing the called function pointer.
3790 * @thread EMT
3791 */
3792static DECLCALLBACK(size_t) pcnetCanReceive(PPDMINETWORKPORT pInterface)
3793{
3794 size_t cb;
3795 int rc;
3796 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
3797
3798 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3799 AssertReleaseRC(rc);
3800
3801 cb = pcnetCanReceiveNoSync(pData);
3802
3803 PDMCritSectLeave(&pData->CritSect);
3804 return cb;
3805}
3806
3807
3808/**
3809 * Receive data from the network.
3810 *
3811 * @returns VBox status code.
3812 * @param pInterface Pointer to the interface structure containing the called function pointer.
3813 * @param pvBuf The available data.
3814 * @param cb Number of bytes available in the buffer.
3815 * @thread EMT
3816 */
3817static DECLCALLBACK(int) pcnetReceive(PPDMINETWORKPORT pInterface, const void *pvBuf, size_t cb)
3818{
3819 PCNetState *pData = INETWORKPORT_2_DATA(pInterface);
3820 int rc;
3821
3822 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
3823 rc = PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
3824 AssertReleaseRC(rc);
3825
3826 if (!pData->fSaving)
3827 {
3828 if (cb > 70) /* unqualified guess */
3829 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
3830 pcnetReceiveNoSync(pData, (const uint8_t*)pvBuf, cb);
3831 pData->Led.Actual.s.fReading = 0;
3832 }
3833 /* otherwise junk the data to Nirwana. */
3834
3835 PDMCritSectLeave(&pData->CritSect);
3836 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
3837
3838 return VINF_SUCCESS;
3839}
3840
3841/** Converts a pointer to PCNetState::INetworkConfig to a PCNetState pointer. */
3842#define INETWORKCONFIG_2_DATA(pInterface) ( (PCNetState *)((uintptr_t)pInterface - RT_OFFSETOF(PCNetState, INetworkConfig)) )
3843
3844
3845/**
3846 * Gets the current Media Access Control (MAC) address.
3847 *
3848 * @returns VBox status code.
3849 * @param pInterface Pointer to the interface structure containing the called function pointer.
3850 * @param pMac Where to store the MAC address.
3851 * @thread EMT
3852 */
3853static DECLCALLBACK(int) pcnetGetMac(PPDMINETWORKCONFIG pInterface, PPDMMAC *pMac)
3854{
3855 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3856 memcpy(pMac, pData->aPROM, sizeof(*pMac));
3857 return VINF_SUCCESS;
3858}
3859
3860
3861/**
3862 * Gets the new link state.
3863 *
3864 * @returns The current link state.
3865 * @param pInterface Pointer to the interface structure containing the called function pointer.
3866 * @thread EMT
3867 */
3868static DECLCALLBACK(PDMNETWORKLINKSTATE) pcnetGetLinkState(PPDMINETWORKCONFIG pInterface)
3869{
3870 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3871 if (pData->fLinkUp && !pData->fLinkTempDown)
3872 return PDMNETWORKLINKSTATE_UP;
3873 if (!pData->fLinkUp)
3874 return PDMNETWORKLINKSTATE_DOWN;
3875 if (pData->fLinkTempDown)
3876 return PDMNETWORKLINKSTATE_DOWN_RESUME;
3877 AssertMsgFailed(("Invalid link state!\n"));
3878 return PDMNETWORKLINKSTATE_INVALID;
3879}
3880
3881
3882/**
3883 * Sets the new link state.
3884 *
3885 * @returns VBox status code.
3886 * @param pInterface Pointer to the interface structure containing the called function pointer.
3887 * @param enmState The new link state
3888 * @thread EMT
3889 */
3890static DECLCALLBACK(int) pcnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
3891{
3892 PCNetState *pData = INETWORKCONFIG_2_DATA(pInterface);
3893 bool fLinkUp;
3894 if ( enmState != PDMNETWORKLINKSTATE_DOWN
3895 && enmState != PDMNETWORKLINKSTATE_UP)
3896 {
3897 AssertMsgFailed(("Invalid parameter enmState=%d\n", enmState));
3898 return VERR_INVALID_PARAMETER;
3899 }
3900
3901 /* has the state changed? */
3902 fLinkUp = enmState == PDMNETWORKLINKSTATE_UP;
3903 if (pData->fLinkUp != fLinkUp)
3904 {
3905 pData->fLinkUp = fLinkUp;
3906 if (fLinkUp)
3907 {
3908 /* connect */
3909 pData->aCSR[0] &= ~(BIT(15) | BIT(13)); /* ERR | CERR - probably not 100% correct either... */
3910 pData->Led.Actual.s.fError = 0;
3911 }
3912 else
3913 {
3914 /* disconnect */
3915 pData->cLinkDownReported = 0;
3916 pData->aCSR[0] |= BIT(15) | BIT(13); /* ERR | CERR (this is probably wrong) */
3917 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
3918 }
3919 Assert(!PDMCritSectIsOwner(&pData->CritSect));
3920 pData->pDrv->pfnNotifyLinkChanged(pData->pDrv, enmState);
3921 }
3922 return VINF_SUCCESS;
3923}
3924
3925
3926/**
3927 * Gets the pointer to the status LED of a unit.
3928 *
3929 * @returns VBox status code.
3930 * @param pInterface Pointer to the interface structure containing the called function pointer.
3931 * @param iLUN The unit which status LED we desire.
3932 * @param ppLed Where to store the LED pointer.
3933 */
3934static DECLCALLBACK(int) pcnetQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
3935{
3936 PCNetState *pData = (PCNetState *)( (uintptr_t)pInterface - RT_OFFSETOF(PCNetState, ILeds) );
3937 if (iLUN == 0)
3938 {
3939 *ppLed = &pData->Led;
3940 return VINF_SUCCESS;
3941 }
3942 return VERR_PDM_LUN_NOT_FOUND;
3943}
3944
3945
3946/**
3947 * @copydoc FNPDMDEVRESET
3948 */
3949static DECLCALLBACK(void) pcnetReset(PPDMDEVINS pDevIns)
3950{
3951 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3952 if (pData->fLinkTempDown)
3953 {
3954 pData->cLinkDownReported = 0x10000;
3955 TMTimerStop(pData->pTimerRestore);
3956 pcnetTimerRestore(pDevIns, pData->pTimerRestore);
3957 }
3958
3959 /** @todo How to flush the queues? */
3960 pcnetHardReset(pData);
3961}
3962
3963
3964/**
3965 * @copydoc FNPDMDEVRELOCATE
3966 */
3967static DECLCALLBACK(void) pcnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
3968{
3969 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3970 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
3971 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
3972 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
3973#ifdef PCNET_NO_POLLING
3974 *(RTHCUINTPTR *)&pData->pfnEMInterpretInstructionGC += offDelta;
3975#else
3976 pData->pTimerPollGC = TMTimerGCPtr(pData->pTimerPollHC);
3977#endif
3978}
3979
3980
3981/**
3982 * Destruct a device instance.
3983 *
3984 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
3985 * resources can be freed correctly.
3986 *
3987 * @returns VBox status.
3988 * @param pDevIns The device instance data.
3989 */
3990static DECLCALLBACK(int) pcnetDestruct(PPDMDEVINS pDevIns)
3991{
3992 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
3993
3994 PDMCritSectEnter(&pData->CritSect, VERR_ACCESS_DENIED);
3995
3996 RTSemEventDestroy(pData->hSendEventSem);
3997 pData->hSendEventSem = 0;
3998 PDMCritSectLeave(&pData->CritSect);
3999
4000 PDMR3CritSectDelete(&pData->CritSect);
4001 return VINF_SUCCESS;
4002}
4003
4004
4005/**
4006 * Construct a device instance for a VM.
4007 *
4008 * @returns VBox status.
4009 * @param pDevIns The device instance data.
4010 * If the registration structure is needed, pDevIns->pDevReg points to it.
4011 * @param iInstance Instance number. Use this to figure out which registers and such to use.
4012 * The device number is also found in pDevIns->iInstance, but since it's
4013 * likely to be freqently used PDM passes it as parameter.
4014 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
4015 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
4016 * iInstance it's expected to be used a bit in this function.
4017 */
4018static DECLCALLBACK(int) pcnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
4019{
4020 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
4021 PPDMIBASE pBase;
4022 char szTmp[128];
4023 int rc;
4024
4025 /* up to four instances are supported */
4026 Assert((iInstance >= 0) && (iInstance < 4));
4027
4028 Assert(RT_ELEMENTS(pData->aBCR) == BCR_MAX_RAP);
4029 Assert(RT_ELEMENTS(pData->aMII) == MII_MAX_REG);
4030 Assert(sizeof(pData->abSendBuf) == RT_ALIGN_Z(sizeof(pData->abSendBuf), 16));
4031
4032 /*
4033 * Validate configuration.
4034 */
4035 if (!CFGMR3AreValuesValid(pCfgHandle, "MAC\0CableConnected\0Am79C973\0GCEnabled\0R0Enabled\0"))
4036 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4037 N_("Invalid configuraton for pcnet device"));
4038
4039 /*
4040 * Read the configuration.
4041 */
4042 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", &pData->MacConfigured, sizeof(pData->MacConfigured));
4043 if (VBOX_FAILURE(rc))
4044 return PDMDEV_SET_ERROR(pDevIns, rc,
4045 N_("Configuration error: Failed to get the \"MAC\" value"));
4046 rc = CFGMR3QueryBool(pCfgHandle, "CableConnected", &pData->fLinkUp);
4047 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4048 pData->fLinkUp = true;
4049 else if (VBOX_FAILURE(rc))
4050 return PDMDEV_SET_ERROR(pDevIns, rc,
4051 N_("Configuration error: Failed to get the \"CableConnected\" value"));
4052
4053 rc = CFGMR3QueryBool(pCfgHandle, "Am79C973", &pData->fAm79C973);
4054 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4055 pData->fAm79C973 = false;
4056 else if (VBOX_FAILURE(rc))
4057 return PDMDEV_SET_ERROR(pDevIns, rc,
4058 N_("Configuration error: Failed to get the \"Am79C973\" value"));
4059
4060#ifdef PCNET_GC_ENABLED
4061 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
4062 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4063 pData->fGCEnabled = true;
4064 else if (VBOX_FAILURE(rc))
4065 return PDMDEV_SET_ERROR(pDevIns, rc,
4066 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
4067
4068 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
4069 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4070 pData->fR0Enabled = true;
4071 else if (VBOX_FAILURE(rc))
4072 return PDMDEV_SET_ERROR(pDevIns, rc,
4073 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
4074
4075#else /* !PCNET_GC_ENABLED */
4076 pData->fGCEnabled = false;
4077 pData->fR0Enabled = false;
4078#endif /* !PCNET_GC_ENABLED */
4079
4080
4081 /*
4082 * Initialize data (most of it anyway).
4083 */
4084 pData->pDevInsHC = pDevIns;
4085 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
4086 pData->Led.u32Magic = PDMLED_MAGIC;
4087 /* IBase */
4088 pData->IBase.pfnQueryInterface = pcnetQueryInterface;
4089 /* INeworkPort */
4090 pData->INetworkPort.pfnCanReceive = pcnetCanReceive;
4091 pData->INetworkPort.pfnReceive = pcnetReceive;
4092 /* INetworkConfig */
4093 pData->INetworkConfig.pfnGetMac = pcnetGetMac;
4094 pData->INetworkConfig.pfnGetLinkState = pcnetGetLinkState;
4095 pData->INetworkConfig.pfnSetLinkState = pcnetSetLinkState;
4096 /* ILeds */
4097 pData->ILeds.pfnQueryStatusLed = pcnetQueryStatusLed;
4098
4099 /* PCI Device */
4100 PCIDevSetVendorId(&pData->PciDev, 0x1022);
4101 PCIDevSetDeviceId(&pData->PciDev, 0x2000);
4102 pData->PciDev.config[0x04] = 0x07; /* command */
4103 pData->PciDev.config[0x05] = 0x00;
4104 pData->PciDev.config[0x06] = 0x80; /* status */
4105 pData->PciDev.config[0x07] = 0x02;
4106 pData->PciDev.config[0x08] = pData->fAm79C973 ? 0x30 : 0x10; /* revision */
4107 pData->PciDev.config[0x09] = 0x00;
4108 pData->PciDev.config[0x0a] = 0x00; /* ethernet network controller */
4109 pData->PciDev.config[0x0b] = 0x02;
4110 pData->PciDev.config[0x0e] = 0x00; /* header_type */
4111
4112 pData->PciDev.config[0x10] = 0x01; /* IO Base */
4113 pData->PciDev.config[0x11] = 0x00;
4114 pData->PciDev.config[0x12] = 0x00;
4115 pData->PciDev.config[0x13] = 0x00;
4116 pData->PciDev.config[0x14] = 0x00; /* MMIO Base */
4117 pData->PciDev.config[0x15] = 0x00;
4118 pData->PciDev.config[0x16] = 0x00;
4119 pData->PciDev.config[0x17] = 0x00;
4120
4121 /* subsystem and subvendor IDs */
4122 pData->PciDev.config[0x2c] = 0x22; /* subsystem vendor id */
4123 pData->PciDev.config[0x2d] = 0x10;
4124 pData->PciDev.config[0x2e] = 0x00; /* subsystem id */
4125 pData->PciDev.config[0x2f] = 0x20;
4126 pData->PciDev.config[0x3d] = 1; /* interrupt pin 0 */
4127 pData->PciDev.config[0x3e] = 0x06;
4128 pData->PciDev.config[0x3f] = 0xff;
4129
4130 /*
4131 * Register the PCI device, its I/O regions, the timer and the saved state item.
4132 */
4133 rc = PDMDevHlpPCIRegister(pDevIns, &pData->PciDev);
4134 if (VBOX_FAILURE(rc))
4135 return rc;
4136 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, PCNET_IOPORT_SIZE,
4137 PCI_ADDRESS_SPACE_IO, pcnetIOPortMap);
4138 if (VBOX_FAILURE(rc))
4139 return rc;
4140 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, PCNET_PNPMMIO_SIZE,
4141 PCI_ADDRESS_SPACE_MEM, pcnetMMIOMap);
4142 if (VBOX_FAILURE(rc))
4143 return rc;
4144
4145#ifdef PCNET_NO_POLLING
4146 rc = PDMR3GetSymbolR0Lazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", &pData->pfnEMInterpretInstructionR0);
4147 if (VBOX_SUCCESS(rc))
4148 {
4149 /*
4150 * Resolve the GC handler.
4151 */
4152 RTGCPTR pfnHandlerGC;
4153 rc = PDMR3GetSymbolGCLazy(PDMDevHlpGetVM(pDevIns), NULL, "EMInterpretInstruction", (RTGCPTR *)&pData->pfnEMInterpretInstructionGC);
4154 }
4155 if (VBOX_FAILURE(rc))
4156 {
4157 AssertMsgFailed(("PDMR3GetSymbolGCLazy -> %Vrc\n", rc));
4158 return rc;
4159 }
4160#else
4161 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimer,
4162 "PCNet Poll Timer", &pData->pTimerPollHC);
4163 if (VBOX_FAILURE(rc))
4164 {
4165 AssertMsgFailed(("pfnTMTimerCreate -> %Vrc\n", rc));
4166 return rc;
4167 }
4168#endif
4169 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, pcnetTimerRestore,
4170 "PCNet Restore Timer", &pData->pTimerRestore);
4171 if (VBOX_FAILURE(rc))
4172 {
4173 AssertMsgFailed(("pfnTMTimerCreate -> %Vrc\n", rc));
4174 return rc;
4175 }
4176/** @todo r=bird: we're not locking down pcnet properly during saving and loading! */
4177 rc = PDMDevHlpSSMRegister(pDevIns, pDevIns->pDevReg->szDeviceName, iInstance,
4178 PCNET_SAVEDSTATE_VERSION, sizeof(*pData),
4179 pcnetSavePrep, pcnetSaveExec, NULL,
4180 NULL, pcnetLoadExec, NULL);
4181 if (VBOX_FAILURE(rc))
4182 return rc;
4183
4184 /*
4185 * Initialize critical section.
4186 * This must of course be done before attaching drivers or anything else which can call us back..
4187 */
4188 char szName[24];
4189 RTStrPrintf(szName, sizeof(szName), "PCNet#%d", iInstance);
4190 rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
4191 if (VBOX_FAILURE(rc))
4192 return rc;
4193
4194 /*
4195 * Create the transmit queue.
4196 */
4197 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4198 pcnetXmitQueueConsumer, true, &pData->pXmitQueueHC);
4199 if (VBOX_FAILURE(rc))
4200 return rc;
4201 pData->pXmitQueueGC = PDMQueueGCPtr(pData->pXmitQueueHC);
4202
4203 /*
4204 * Create the RX notifer signaller.
4205 */
4206 rc = PDMDevHlpPDMQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
4207 pcnetCanRxQueueConsumer, true, &pData->pCanRxQueueHC);
4208 if (VBOX_FAILURE(rc))
4209 return rc;
4210 pData->pCanRxQueueGC = PDMQueueGCPtr(pData->pCanRxQueueHC);
4211
4212 /*
4213 * Register the info item.
4214 */
4215 RTStrPrintf(szTmp, sizeof(szTmp), "pcnet%d", pDevIns->iInstance);
4216 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "PCNET info.", pcnetInfo);
4217
4218 /*
4219 * Attach status driver (optional).
4220 */
4221 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->IBase, &pBase, "Status Port");
4222 if (VBOX_SUCCESS(rc))
4223 pData->pLedsConnector = (PPDMILEDCONNECTORS)
4224 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
4225 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
4226 {
4227 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
4228 return rc;
4229 }
4230
4231 /*
4232 * Attach driver.
4233 */
4234 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Network Port");
4235 if (VBOX_SUCCESS(rc))
4236 {
4237 if (rc == VINF_NAT_DNS)
4238 {
4239#ifdef RT_OS_LINUX
4240 VMSetRuntimeError(PDMDevHlpGetVM(pDevIns), false, "NoDNSforNAT",
4241 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"));
4242#else
4243 VMSetRuntimeError(PDMDevHlpGetVM(pDevIns), false, "NoDNSforNAT",
4244 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"));
4245#endif
4246 }
4247 pData->pDrv = (PPDMINETWORKCONNECTOR)
4248 pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
4249 if (!pData->pDrv)
4250 {
4251 AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
4252 return VERR_PDM_MISSING_INTERFACE_BELOW;
4253 }
4254 }
4255 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
4256 Log(("No attached driver!\n"));
4257 else
4258 return rc;
4259
4260 /*
4261 * Reset the device state. (Do after attaching.)
4262 */
4263 pcnetHardReset(pData);
4264
4265 /* Create send queue for the async send thread. */
4266 rc = RTSemEventCreate(&pData->hSendEventSem);
4267 AssertRC(rc);
4268
4269 /* Create asynchronous thread */
4270 rc = RTThreadCreate(&pData->hSendThread, pcnetAsyncSend, (void *)pData, 128*1024, RTTHREADTYPE_IO, 0, "PCNET_SEND");
4271 AssertRC(rc);
4272
4273#ifdef VBOX_WITH_STATISTICS
4274 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in GC", "/Devices/PCNet%d/MMIO/ReadGC", iInstance);
4275 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO reads in HC", "/Devices/PCNet%d/MMIO/ReadHC", iInstance);
4276 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in GC", "/Devices/PCNet%d/MMIO/WriteGC", iInstance);
4277 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMMIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling MMIO writes in HC", "/Devices/PCNet%d/MMIO/WriteHC", iInstance);
4278 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMRead, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM reads", "/Devices/PCNet%d/IO/APROMRead", iInstance);
4279 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatAPROMWrite, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling APROM writes", "/Devices/PCNet%d/IO/APROMWrite", iInstance);
4280 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in GC", "/Devices/PCNet%d/IO/ReadGC", iInstance);
4281 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNetIO reads in HC", "/Devices/PCNet%d/IO/ReadHC", iInstance);
4282 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in GC", "/Devices/PCNet%d/IO/WriteGC", iInstance);
4283 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet IO writes in HC", "/Devices/PCNet%d/IO/WriteHC", iInstance);
4284 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet Timer", "/Devices/PCNet%d/Timer", iInstance);
4285 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet receive", "/Devices/PCNet%d/Receive", iInstance);
4286 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet transmit in HC", "/Devices/PCNet%d/Transmit/Total", iInstance);
4287 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet send transmit in HC", "/Devices/PCNet%d/Transmit/Send", iInstance);
4288 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in GC", "/Devices/PCNet%d/TdtePollGC", iInstance);
4289 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TdtePoll in HC", "/Devices/PCNet%d/TdtePollHC", iInstance);
4290 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRdtePollGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in GC", "/Devices/PCNet%d/RdtePollGC", iInstance);
4291 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRdtePollHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet RdtePoll in HC", "/Devices/PCNet%d/RdtePollHC", iInstance);
4292
4293 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTmdStoreGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in GC", "/Devices/PCNet%d/TmdStoreGC", iInstance);
4294 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTmdStoreHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet TmdStore in HC", "/Devices/PCNet%d/TmdStoreHC", iInstance);
4295
4296 unsigned i;
4297 for (i = 0; i < ELEMENTS(pData->aStatXmitFlush) - 1; i++)
4298 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d", iInstance, i + 1);
4299 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitFlush[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitFlushIrq/%d+", iInstance, i + 1);
4300
4301 for (i = 0; i < ELEMENTS(pData->aStatXmitChainCounts) - 1; i++)
4302 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d", iInstance, i + 1);
4303 PDMDevHlpSTAMRegisterF(pDevIns, &pData->aStatXmitChainCounts[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/XmitChainCounts/%d+", iInstance, i + 1);
4304
4305 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatXmitSkipCurrent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "", "/Devices/PCNet%d/Xmit/Skipped", iInstance, i + 1);
4306
4307 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet interrupt checks", "/Devices/PCNet%d/Interrupt", iInstance);
4308 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatPollTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling PCNet poll timer", "/Devices/PCNet%d/PollTimer", iInstance);
4309 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatMIIReads, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of MII reads", "/Devices/PCNet%d/MIIReads", iInstance);
4310# ifdef PCNET_NO_POLLING
4311 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRCVRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of receive ring writes", "/Devices/PCNet%d/Ring/RCVWrites", iInstance);
4312 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatTXRingWrite, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of transmit ring writes", "/Devices/PCNet%d/Ring/TXWrites", iInstance);
4313 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/HC/Writes", iInstance);
4314 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/R0/Writes", iInstance);
4315 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored ring page writes", "/Devices/PCNet%d/Ring/GC/Writes", iInstance);
4316 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/HC/Failed", iInstance);
4317 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/R0/Failed", iInstance);
4318 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteFailedGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of failed ring page writes", "/Devices/PCNet%d/Ring/GC/Failed", iInstance);
4319 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeHC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/HC/Outside", iInstance);
4320 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeR0, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/R0/Outside", iInstance);
4321 PDMDevHlpSTAMRegisterF(pDevIns, &pData->StatRingWriteOutsideRangeGC, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of monitored writes outside ring range", "/Devices/PCNet%d/Ring/GC/Outside", iInstance);
4322# endif /* PCNET_NO_POLLING */
4323#endif
4324
4325 return VINF_SUCCESS;
4326}
4327
4328
4329/**
4330 * The device registration structure.
4331 */
4332const PDMDEVREG g_DevicePCNet =
4333{
4334 /* u32Version */
4335 PDM_DEVREG_VERSION,
4336 /* szDeviceName */
4337 "pcnet",
4338 /* szGCMod */
4339#ifdef PCNET_GC_ENABLED
4340 "VBoxDDGC.gc",
4341 "VBoxDDR0.r0",
4342#else
4343 "",
4344 "",
4345#endif
4346 /* pszDescription */
4347 "AMD PC-Net II Ethernet controller.\n",
4348 /* fFlags */
4349#ifdef PCNET_GC_ENABLED
4350 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
4351#else
4352 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
4353#endif
4354 /* fClass */
4355 PDM_DEVREG_CLASS_NETWORK,
4356 /* cMaxInstances */
4357 4,
4358 /* cbInstance */
4359 sizeof(PCNetState),
4360 /* pfnConstruct */
4361 pcnetConstruct,
4362 /* pfnDestruct */
4363 pcnetDestruct,
4364 /* pfnRelocate */
4365 pcnetRelocate,
4366 /* pfnIOCtl */
4367 NULL,
4368 /* pfnPowerOn */
4369 NULL,
4370 /* pfnReset */
4371 pcnetReset,
4372 /* pfnSuspend */
4373 NULL,
4374 /* pfnResume */
4375 NULL,
4376 /* pfnAttach */
4377 NULL,
4378 /* pfnDetach */
4379 NULL,
4380 /* pfnQueryInterface. */
4381 NULL
4382};
4383
4384#endif /* IN_RING3 */
4385#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
4386
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