VirtualBox

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

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

More stats

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