VirtualBox

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

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

Update

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

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