VirtualBox

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

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

#pragma pack(1) not necessary? We will see if AssertCompileSize() triggers...

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