VirtualBox

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

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

prevent RX/TX during suspend

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