VirtualBox

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

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

DevPCNet.cpp: MSC/64 size_t warning.

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