VirtualBox

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

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

Changed comments

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

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