VirtualBox

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

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

Make our devices use the RTGCPHYS32 type & backed out the alignment changes
Added SSMR3PutGCPhys32 & SSMR3GetGCPhys32
Removed obsolete VBOX types

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