VirtualBox

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

Last change on this file since 8483 was 8314, checked in by vboxsync, 17 years ago

sanity check

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