VirtualBox

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

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

InnoTek -> innotek: all the headers and comments.

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