VirtualBox

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

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

pcnet: another correction for the physwrite hack

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

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