VirtualBox

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

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

More comments

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