VirtualBox

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

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

Fixed the no polling code.

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