VirtualBox

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

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

Added a bunch of pci register defines and created a couple of the setters/getters that should be created to make that pci config setup easier to read.

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