VirtualBox

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

最後變更 在這個檔案從23253是 23101,由 vboxsync 提交於 16 年 前

DevPCNet: fixed rare case of RX freezing

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette