VirtualBox

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

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

prelimiary network statistics (to be improved)

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette