VirtualBox

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

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

replace underscore symbols in Devices/

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