VirtualBox

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

Last change on this file since 5320 was 5067, checked in by vboxsync, 17 years ago

amd64 fix

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