VirtualBox

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

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

Try to deal with illegal descriptors

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

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