VirtualBox

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

Last change on this file since 14419 was 14419, checked in by vboxsync, 16 years ago

Call DGFStop instead of returning VERR_INTERNAL_ERROR on I/O port access (avoids guru meditation).

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