VirtualBox

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

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

pcnet: save some cycles by returning early if we don't own the descriptor

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