VirtualBox

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

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

shorten some thread names, looks better as log prefix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 181.8 KB
Line 
1/* $Id: DevPCNet.cpp 7321 2008-03-06 14:03:20Z 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 * @return true if we own the descriptor, false otherwise
604 */
605DECLINLINE(bool) pcnetTmdLoad(PCNetState *pData, TMD *tmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
606{
607 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
608 uint8_t ownbyte;
609
610 if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
611 {
612 uint16_t xda[4];
613
614 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
615 if (!(ownbyte & 0x80) && fRetIfNotOwn)
616 return false;
617 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
618 ((uint32_t *)tmd)[0] = (uint32_t)xda[0] | ((uint32_t)(xda[1] & 0x00ff) << 16);
619 ((uint32_t *)tmd)[1] = (uint32_t)xda[2] | ((uint32_t)(xda[1] & 0xff00) << 16);
620 ((uint32_t *)tmd)[2] = (uint32_t)xda[3] << 16;
621 ((uint32_t *)tmd)[3] = 0;
622 }
623 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
624 {
625 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
626 if (!(ownbyte & 0x80) && fRetIfNotOwn)
627 return false;
628 PDMDevHlpPhysRead(pDevIns, addr, (void*)tmd, 16);
629 }
630 else
631 {
632 uint32_t xda[4];
633 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
634 if (!(ownbyte & 0x80) && fRetIfNotOwn)
635 return false;
636 PDMDevHlpPhysRead(pDevIns, addr, (void*)&xda[0], sizeof(xda));
637 ((uint32_t *)tmd)[0] = xda[2];
638 ((uint32_t *)tmd)[1] = xda[1];
639 ((uint32_t *)tmd)[2] = xda[0];
640 ((uint32_t *)tmd)[3] = xda[3];
641 }
642 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
643#ifdef DEBUG
644 if (tmd->tmd1.own == 1 && !(ownbyte & 0x80))
645 Log(("pcnetTmdLoad: own bit flipped while reading!!\n"));
646#endif
647 if (!(ownbyte & 0x80))
648 tmd->tmd1.own = 0;
649
650 return !!tmd->tmd1.own;
651}
652
653/**
654 * Store transmit message descriptor and hand it over to the host (the VM guest).
655 * Make sure that all data are transmitted before we clear the own flag.
656 */
657DECLINLINE(void) pcnetTmdStorePassHost(PCNetState *pData, TMD *tmd, RTGCPHYS32 addr)
658{
659 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTmdStore), a);
660 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
661 if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
662 {
663 uint16_t xda[4];
664 xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
665 xda[1] = ((((uint32_t *)tmd)[0] >> 16) & 0xff) | ((((uint32_t *)tmd)[1]>>16) & 0xff00);
666 xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
667 xda[3] = ((uint32_t *)tmd)[2] >> 16;
668 xda[1] |= 0x8000;
669 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
670 xda[1] &= ~0x8000;
671 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)xda + 3, 1);
672 }
673 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
674 {
675 ((uint32_t*)tmd)[1] |= 0x80000000;
676 PDMDevHlpPhysWrite(pDevIns, addr, (void*)tmd, 16);
677 ((uint32_t*)tmd)[1] &= ~0x80000000;
678 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)tmd + 7, 1);
679 }
680 else
681 {
682 uint32_t xda[4];
683 xda[0] = ((uint32_t *)tmd)[2];
684 xda[1] = ((uint32_t *)tmd)[1];
685 xda[2] = ((uint32_t *)tmd)[0];
686 xda[3] = ((uint32_t *)tmd)[3];
687 xda[1] |= 0x80000000;
688 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&xda[0], sizeof(xda));
689 xda[1] &= ~0x80000000;
690 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)xda + 7, 1);
691 }
692 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTmdStore), a);
693}
694
695/**
696 * Load receive message descriptor
697 * Make sure we read the own flag first.
698 *
699 * @param pData adapter private data
700 * @param addr physical address of the descriptor
701 * @param fRetIfNotOwn return immediately after reading the own flag if we don't own the descriptor
702 * @return true if we own the descriptor, false otherwise
703 */
704DECLINLINE(int) pcnetRmdLoad(PCNetState *pData, RMD *rmd, RTGCPHYS32 addr, bool fRetIfNotOwn)
705{
706 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
707 uint8_t ownbyte;
708
709 if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
710 {
711 uint16_t rda[4];
712 PDMDevHlpPhysRead(pDevIns, addr+3, &ownbyte, 1);
713 if ((!ownbyte & 0x80) && fRetIfNotOwn)
714 return false;
715 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
716 ((uint32_t *)rmd)[0] = (uint32_t)rda[0] | ((rda[1] & 0x00ff) << 16);
717 ((uint32_t *)rmd)[1] = (uint32_t)rda[2] | ((rda[1] & 0xff00) << 16);
718 ((uint32_t *)rmd)[2] = (uint32_t)rda[3];
719 ((uint32_t *)rmd)[3] = 0;
720 }
721 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
722 {
723 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
724 if ((!ownbyte & 0x80) && fRetIfNotOwn)
725 return false;
726 PDMDevHlpPhysRead(pDevIns, addr, (void*)rmd, 16);
727 }
728 else
729 {
730 uint32_t rda[4];
731 PDMDevHlpPhysRead(pDevIns, addr+7, &ownbyte, 1);
732 if ((!ownbyte & 0x80) && fRetIfNotOwn)
733 return false;
734 PDMDevHlpPhysRead(pDevIns, addr, (void*)&rda[0], sizeof(rda));
735 ((uint32_t *)rmd)[0] = rda[2];
736 ((uint32_t *)rmd)[1] = rda[1];
737 ((uint32_t *)rmd)[2] = rda[0];
738 ((uint32_t *)rmd)[3] = rda[3];
739 }
740 /* Double check the own bit; guest drivers might be buggy and lock prefixes in the recompiler are ignored by other threads. */
741#ifdef DEBUG
742 if (rmd->rmd1.own == 1 && !(ownbyte & 0x80))
743 Log(("pcnetRmdLoad: own bit flipped while reading!!\n"));
744#endif
745 if (!(ownbyte & 0x80))
746 rmd->rmd1.own = 0;
747
748 return !!rmd->rmd1.own;
749}
750
751/**
752 * Store receive message descriptor and hand it over to the host (the VM guest).
753 * Make sure that all data are transmitted before we clear the own flag.
754 */
755DECLINLINE(void) pcnetRmdStorePassHost(PCNetState *pData, RMD *rmd, RTGCPHYS32 addr)
756{
757 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
758 if (RT_UNLIKELY(BCR_SWSTYLE(pData) == 0))
759 {
760 uint16_t rda[4];
761 rda[0] = ((uint32_t *)rmd)[0] & 0xffff;
762 rda[1] = ((((uint32_t *)rmd)[0]>>16) & 0xff) | ((((uint32_t *)rmd)[1]>>16) & 0xff00);
763 rda[2] = ((uint32_t *)rmd)[1] & 0xffff;
764 rda[3] = ((uint32_t *)rmd)[2] & 0xffff;
765 rda[1] |= 0x8000;
766 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
767 rda[1] &= ~0x8000;
768 PDMDevHlpPhysWrite(pDevIns, addr+3, (uint8_t*)rda + 3, 1);
769 }
770 else if (RT_LIKELY(BCR_SWSTYLE(pData) != 3))
771 {
772 ((uint32_t*)rmd)[1] |= 0x80000000;
773 PDMDevHlpPhysWrite(pDevIns, addr, (void*)rmd, 16);
774 ((uint32_t*)rmd)[1] &= ~0x80000000;
775 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rmd + 7, 1);
776 }
777 else
778 {
779 uint32_t rda[4];
780 rda[0] = ((uint32_t *)rmd)[2];
781 rda[1] = ((uint32_t *)rmd)[1];
782 rda[2] = ((uint32_t *)rmd)[0];
783 rda[3] = ((uint32_t *)rmd)[3];
784 rda[1] |= 0x80000000;
785 PDMDevHlpPhysWrite(pDevIns, addr, (void*)&rda[0], sizeof(rda));
786 rda[1] &= ~0x80000000;
787 PDMDevHlpPhysWrite(pDevIns, addr+7, (uint8_t*)rda + 7, 1);
788 }
789}
790
791/** Checks if it's a bad (as in invalid) RMD.*/
792#define IS_RMD_BAD(rmd) ((rmd).rmd1.ones != 15 || (rmd).rmd2.zeros != 0)
793
794/** The network card is the owner of the RDTE/TDTE, actually it is this driver */
795#define CARD_IS_OWNER(desc) (((desc) & 0x8000))
796
797/** The host is the owner of the RDTE/TDTE -- actually the VM guest. */
798#define HOST_IS_OWNER(desc) (!((desc) & 0x8000))
799
800#ifndef ETHER_IS_MULTICAST /* Net/Open BSD macro it seems */
801#define ETHER_IS_MULTICAST(a) ((*(uint8_t *)(a)) & 1)
802#endif
803
804#define ETHER_ADDR_LEN ETH_ALEN
805#define ETH_ALEN 6
806#pragma pack(1)
807struct ether_header
808{
809 uint8_t ether_dhost[ETH_ALEN]; /**< destination ethernet address */
810 uint8_t ether_shost[ETH_ALEN]; /**< source ethernet address */
811 uint16_t ether_type; /**< packet type ID field */
812};
813#pragma pack()
814
815#ifdef LOG_PACKETS
816static void LogPkt(const char *name, const void *const src, int count)
817{
818 int i, j;
819 const uint8_t * const p = (const uint8_t * const)src;
820 LogRel(("%s: ", name));
821 i = 14; // length of MAC header
822 i += 4*(p[i] & 15); // length of IP header
823 i += 4*(p[i+12] >> 4); // length of TCP header
824 for (j=i; j<70 && j<count; j++)
825 LogRel((" %02x", p[j]));
826 LogRel((" ("));
827 for (j=i; j<70 && j<count; j++)
828 LogRel(("%c", p[j] >= 32 && p[j] < 127 ? p[j] : '.'));
829 LogRel((")\n"));
830}
831#endif
832
833#define PRINT_PKTHDR(BUF) do { \
834 struct ether_header *hdr = (struct ether_header *)(BUF); \
835 Log(("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
836 "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
837 "type=%#06x (bcast=%d)\n", \
838 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
839 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
840 hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
841 hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
842 htons(hdr->ether_type), \
843 !!ETHER_IS_MULTICAST(hdr->ether_dhost))); \
844} while (0)
845
846
847#ifdef IN_RING3
848
849#define MULTICAST_FILTER_LEN 8
850
851DECLINLINE(uint32_t) lnc_mchash(const uint8_t *ether_addr)
852{
853#define LNC_POLYNOMIAL 0xEDB88320UL
854 uint32_t crc = 0xFFFFFFFF;
855 int idx, bit;
856 uint8_t data;
857
858 for (idx = 0; idx < ETHER_ADDR_LEN; idx++)
859 {
860 for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++)
861 {
862 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
863 data >>= 1;
864 }
865 }
866 return crc;
867#undef LNC_POLYNOMIAL
868}
869
870#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
871
872/* generated using the AUTODIN II polynomial
873 * x^32 + x^26 + x^23 + x^22 + x^16 +
874 * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
875 */
876static const uint32_t crctab[256] =
877{
878 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
879 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
880 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
881 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
882 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
883 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
884 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
885 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
886 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
887 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
888 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
889 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
890 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
891 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
892 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
893 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
894 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
895 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
896 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
897 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
898 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
899 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
900 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
901 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
902 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
903 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
904 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
905 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
906 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
907 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
908 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
909 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
910 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
911 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
912 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
913 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
914 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
915 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
916 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
917 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
918 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
919 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
920 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
921 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
922 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
923 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
924 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
925 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
926 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
927 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
928 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
929 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
930 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
931 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
932 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
933 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
934 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
935 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
936 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
937 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
938 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
939 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
940 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
941 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
942};
943
944DECLINLINE(int) padr_match(PCNetState *pData, const uint8_t *buf, int size)
945{
946 struct ether_header *hdr = (struct ether_header *)buf;
947 int result;
948#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && !defined(PCNET_DEBUG_MATCH)
949 result = !CSR_DRCVPA(pData) && !memcmp(hdr->ether_dhost, pData->aCSR + 12, 6);
950#else
951 uint8_t padr[6];
952 padr[0] = pData->aCSR[12] & 0xff;
953 padr[1] = pData->aCSR[12] >> 8;
954 padr[2] = pData->aCSR[13] & 0xff;
955 padr[3] = pData->aCSR[13] >> 8;
956 padr[4] = pData->aCSR[14] & 0xff;
957 padr[5] = pData->aCSR[14] >> 8;
958 result = !CSR_DRCVPA(pData) && !memcmp(hdr->ether_dhost, padr, 6);
959#endif
960
961#ifdef PCNET_DEBUG_MATCH
962 Log(("#%d packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
963 "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
964 PCNETSTATE_2_DEVINS(pData)->iInstance,
965 hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
966 hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
967 padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]));
968 Log(("padr_match result=%d\n", result));
969#endif
970 return result;
971}
972
973DECLINLINE(int) padr_bcast(PCNetState *pData, const uint8_t *buf, int size)
974{
975 static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
976 struct ether_header *hdr = (struct ether_header *)buf;
977 int result = !CSR_DRCVBC(pData) && !memcmp(hdr->ether_dhost, aBCAST, 6);
978#ifdef PCNET_DEBUG_MATCH
979 Log(("#%d padr_bcast result=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, result));
980#endif
981 return result;
982}
983
984static int ladr_match(PCNetState *pData, const uint8_t *buf, int size)
985{
986 struct ether_header *hdr = (struct ether_header *)buf;
987 if (RT_UNLIKELY(hdr->ether_dhost[0] & 0x01) && ((uint64_t *)&pData->aCSR[8])[0] != 0LL)
988 {
989 int index;
990#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
991 index = lnc_mchash(hdr->ether_dhost) >> 26;
992 return ((uint8_t*)(pData->aCSR + 8))[index >> 3] & (1 << (index & 7));
993#else
994 uint8_t ladr[8];
995 ladr[0] = pData->aCSR[8] & 0xff;
996 ladr[1] = pData->aCSR[8] >> 8;
997 ladr[2] = pData->aCSR[9] & 0xff;
998 ladr[3] = pData->aCSR[9] >> 8;
999 ladr[4] = pData->aCSR[10] & 0xff;
1000 ladr[5] = pData->aCSR[10] >> 8;
1001 ladr[6] = pData->aCSR[11] & 0xff;
1002 ladr[7] = pData->aCSR[11] >> 8;
1003 index = lnc_mchash(hdr->ether_dhost) >> 26;
1004 return (ladr[index >> 3] & (1 << (index & 7)));
1005#endif
1006 }
1007 return 0;
1008}
1009
1010#endif /* IN_RING3 */
1011
1012/**
1013 * Get the receive descriptor ring address with a given index.
1014 */
1015DECLINLINE(RTGCPHYS32) pcnetRdraAddr(PCNetState *pData, int idx)
1016{
1017 return pData->GCRDRA + ((CSR_RCVRL(pData) - idx) << pData->iLog2DescSize);
1018}
1019
1020/**
1021 * Get the transmit descriptor ring address with a given index.
1022 */
1023DECLINLINE(RTGCPHYS32) pcnetTdraAddr(PCNetState *pData, int idx)
1024{
1025 return pData->GCTDRA + ((CSR_XMTRL(pData) - idx) << pData->iLog2DescSize);
1026}
1027
1028__BEGIN_DECLS
1029PDMBOTHCBDECL(int) pcnetIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
1030 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1031PDMBOTHCBDECL(int) pcnetIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
1032 RTIOPORT Port, uint32_t u32, unsigned cb);
1033PDMBOTHCBDECL(int) pcnetIOPortAPromWrite(PPDMDEVINS pDevIns, void *pvUser,
1034 RTIOPORT Port, uint32_t u32, unsigned cb);
1035PDMBOTHCBDECL(int) pcnetIOPortAPromRead(PPDMDEVINS pDevIns, void *pvUser,
1036 RTIOPORT Port, uint32_t *pu32, unsigned cb);
1037PDMBOTHCBDECL(int) pcnetMMIORead(PPDMDEVINS pDevIns, void *pvUser,
1038 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1039PDMBOTHCBDECL(int) pcnetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser,
1040 RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
1041#ifndef IN_RING3
1042DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1043 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
1044#endif
1045__END_DECLS
1046
1047#undef htonl
1048#define htonl(x) ASMByteSwapU32(x)
1049#undef htons
1050#define htons(x) ( (((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8) )
1051
1052static void pcnetPollRxTx(PCNetState *pData);
1053static void pcnetPollTimer(PCNetState *pData);
1054static void pcnetUpdateIrq(PCNetState *pData);
1055static uint32_t pcnetBCRReadU16(PCNetState *pData, uint32_t u32RAP);
1056static int pcnetBCRWriteU16(PCNetState *pData, uint32_t u32RAP, uint32_t val);
1057
1058
1059#ifdef PCNET_NO_POLLING
1060# ifndef IN_RING3
1061
1062/**
1063 * #PF Virtual Handler callback for Guest write access to the ring descriptor page(pData)
1064 *
1065 * @return VBox status code (appropriate for trap handling and GC return).
1066 * @param pVM VM Handle.
1067 * @param uErrorCode CPU Error code.
1068 * @param pRegFrame Trap register frame.
1069 * @param pvFault The fault address (cr2).
1070 * @param GCPhysFault The GC physical address corresponding to pvFault.
1071 * @param pvUser User argument.
1072 */
1073DECLEXPORT(int) pcnetHandleRingWrite(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1074 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1075{
1076 PCNetState *pData = (PCNetState *)pvUser;
1077
1078 Log(("#%d pcnetHandleRingWriteGC: write to %#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, GCPhysFault));
1079
1080 uint32_t cb;
1081 int rc = CTXALLSUFF(pData->pfnEMInterpretInstruction)(pVM, pRegFrame, pvFault, &cb);
1082 if (VBOX_SUCCESS(rc) && cb)
1083 {
1084 if ( (GCPhysFault >= pData->GCTDRA && GCPhysFault + cb < pcnetTdraAddr(pData, 0))
1085#ifdef PCNET_MONITOR_RECEIVE_RING
1086 || (GCPhysFault >= pData->GCRDRA && GCPhysFault + cb < pcnetRdraAddr(pData, 0))
1087#endif
1088 )
1089 {
1090 uint32_t offsetTDRA = (GCPhysFault - pData->GCTDRA);
1091
1092 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1093 if (VBOX_SUCCESS(rc))
1094 {
1095 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWrite)); ;
1096
1097 /* Check if we can do something now */
1098 pcnetPollRxTx(pData);
1099 pcnetUpdateIrq(pData);
1100
1101 PDMCritSectLeave(&pData->CritSect);
1102 return VINF_SUCCESS;
1103 }
1104 }
1105 else
1106 {
1107 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteOutsideRange)); ;
1108 return VINF_SUCCESS; /* outside of the ring range */
1109 }
1110 }
1111 STAM_COUNTER_INC(&CTXALLSUFF(pData->StatRingWriteFailed)); ;
1112 return VINF_IOM_HC_MMIO_WRITE; /* handle in ring3 */
1113}
1114
1115# else /* IN_RING3 */
1116
1117/**
1118 * #PF Handler callback for physical access handler ranges (MMIO among others) in HC.
1119 *
1120 * The handler can not raise any faults, it's mainly for monitoring write access
1121 * to certain pages.
1122 *
1123 * @returns VINF_SUCCESS if the handler have carried out the operation.
1124 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1125 * @param pVM VM Handle.
1126 * @param GCPhys The physical address the guest is writing to.
1127 * @param pvPhys The HC mapping of that address.
1128 * @param pvBuf What the guest is reading/writing.
1129 * @param cbBuf How much it's reading/writing.
1130 * @param enmAccessType The access type.
1131 * @param pvUser User argument.
1132 */
1133static DECLCALLBACK(int) pcnetHandleRingWrite(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf,
1134 size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1135{
1136 PPDMDEVINS pDevIns = (PPDMDEVINS)pvUser;
1137 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1138
1139 Log(("#%d pcnetHandleRingWrite: write to %#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, GCPhys));
1140#ifdef VBOX_WITH_STATISTICS
1141 STAM_COUNTER_INC(&CTXSUFF(pData->StatRingWrite));
1142 if (GCPhys >= pData->GCRDRA && GCPhys < pcnetRdraAddr(pData, 0))
1143 STAM_COUNTER_INC(&pData->StatRCVRingWrite);
1144 else if (GCPhys >= pData->GCTDRA && GCPhys < pcnetTdraAddr(pData, 0))
1145 STAM_COUNTER_INC(&pData->StatTXRingWrite);
1146#endif
1147 /* Perform the actual write */
1148 memcpy((char *)pvPhys, pvBuf, cbBuf);
1149
1150 /* Writes done by our code don't require polling of course */
1151 if (PDMCritSectIsOwner(&pData->CritSect) == false)
1152 {
1153 if ( (GCPhys >= pData->GCTDRA && GCPhys + cbBuf < pcnetTdraAddr(pData, 0))
1154#ifdef PCNET_MONITOR_RECEIVE_RING
1155 || (GCPhys >= pData->GCRDRA && GCPhys + cbBuf < pcnetRdraAddr(pData, 0))
1156#endif
1157 )
1158 {
1159 int rc = PDMCritSectEnter(&pData->CritSect, VERR_SEM_BUSY);
1160 AssertReleaseRC(rc);
1161 /* Check if we can do something now */
1162 pcnetPollRxTx(pData);
1163 pcnetUpdateIrq(pData);
1164 PDMCritSectLeave(&pData->CritSect);
1165 }
1166 }
1167 return VINF_SUCCESS;
1168}
1169# endif /* !IN_RING3 */
1170#endif /* PCNET_NO_POLLING */
1171
1172static void pcnetSoftReset(PCNetState *pData)
1173{
1174 Log(("#%d pcnetSoftReset:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1175
1176 pData->u32Lnkst = 0x40;
1177 pData->GCRDRA = 0;
1178 pData->GCTDRA = 0;
1179 pData->u32RAP = 0;
1180
1181 pData->aBCR[BCR_BSBC] &= ~0x0080;
1182
1183 pData->aCSR[0] = 0x0004;
1184 pData->aCSR[3] = 0x0000;
1185 pData->aCSR[4] = 0x0115;
1186 pData->aCSR[5] = 0x0000;
1187 pData->aCSR[6] = 0x0000;
1188 pData->aCSR[8] = 0;
1189 pData->aCSR[9] = 0;
1190 pData->aCSR[10] = 0;
1191 pData->aCSR[11] = 0;
1192 pData->aCSR[12] = RT_LE2H_U16(((uint16_t *)&pData->aPROM[0])[0]);
1193 pData->aCSR[13] = RT_LE2H_U16(((uint16_t *)&pData->aPROM[0])[1]);
1194 pData->aCSR[14] = RT_LE2H_U16(((uint16_t *)&pData->aPROM[0])[2]);
1195 pData->aCSR[15] &= 0x21c4;
1196 CSR_RCVRC(pData) = 1;
1197 CSR_XMTRC(pData) = 1;
1198 CSR_RCVRL(pData) = 1;
1199 CSR_XMTRL(pData) = 1;
1200 pData->aCSR[80] = 0x1410;
1201 pData->aCSR[88] = pData->fAm79C973 ? CSR_VERSION_LOW_79C973 : CSR_VERSION_LOW_79C970A;
1202 pData->aCSR[89] = CSR_VERSION_HIGH;
1203 pData->aCSR[94] = 0x0000;
1204 pData->aCSR[100] = 0x0200;
1205 pData->aCSR[103] = 0x0105;
1206 pData->aCSR[103] = 0x0105;
1207 CSR_MISSC(pData) = 0;
1208 pData->aCSR[114] = 0x0000;
1209 pData->aCSR[122] = 0x0000;
1210 pData->aCSR[124] = 0x0000;
1211}
1212
1213/**
1214 * Check if we have to send an interrupt to the guest. An interrupt can occur on
1215 * - csr0 (written quite often)
1216 * - csr4 (only written by pcnetSoftReset(), pcnetStop() or by the guest driver)
1217 * - csr5 (only written by pcnetSoftReset(), pcnetStop or by the driver guest)
1218 */
1219static void pcnetUpdateIrq(PCNetState *pData)
1220{
1221 register int iISR = 0;
1222 register uint16_t csr0 = pData->aCSR[0];
1223
1224 csr0 &= ~0x0080; /* clear INTR */
1225
1226 STAM_PROFILE_ADV_START(&pData->StatInterrupt, a);
1227
1228 /* Linux guests set csr4=0x0915
1229 * W2k guests set csr3=0x4940 (disable BABL, MERR, IDON, DXSUFLO */
1230
1231#if 1
1232 if ( ( (csr0 & ~pData->aCSR[3]) & 0x5f00)
1233 || (((pData->aCSR[4]>>1) & ~pData->aCSR[4]) & 0x0115)
1234 || (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0048))
1235#else
1236 if ( ( !(pData->aCSR[3] & 0x4000) && !!(csr0 & 0x4000)) /* BABL */
1237 ||( !(pData->aCSR[3] & 0x1000) && !!(csr0 & 0x1000)) /* MISS */
1238 ||( !(pData->aCSR[3] & 0x0100) && !!(csr0 & 0x0100)) /* IDON */
1239 ||( !(pData->aCSR[3] & 0x0200) && !!(csr0 & 0x0200)) /* TINT */
1240 ||( !(pData->aCSR[3] & 0x0400) && !!(csr0 & 0x0400)) /* RINT */
1241 ||( !(pData->aCSR[3] & 0x0800) && !!(csr0 & 0x0800)) /* MERR */
1242 ||( !(pData->aCSR[4] & 0x0001) && !!(pData->aCSR[4] & 0x0002)) /* JAB */
1243 ||( !(pData->aCSR[4] & 0x0004) && !!(pData->aCSR[4] & 0x0008)) /* TXSTRT */
1244 ||( !(pData->aCSR[4] & 0x0010) && !!(pData->aCSR[4] & 0x0020)) /* RCVO */
1245 ||( !(pData->aCSR[4] & 0x0100) && !!(pData->aCSR[4] & 0x0200)) /* MFCO */
1246 ||(!!(pData->aCSR[5] & 0x0040) && !!(pData->aCSR[5] & 0x0080)) /* EXDINT */
1247 ||(!!(pData->aCSR[5] & 0x0008) && !!(pData->aCSR[5] & 0x0010)) /* MPINT */)
1248#endif
1249 {
1250 iISR = !!(csr0 & 0x0040); /* CSR_INEA */
1251 csr0 |= 0x0080; /* set INTR */
1252 }
1253
1254#ifdef VBOX
1255 if (pData->aCSR[4] & 0x0080) /* UINTCMD */
1256 {
1257 pData->aCSR[4] &= ~0x0080; /* clear UINTCMD */
1258 pData->aCSR[4] |= 0x0040; /* set UINT */
1259 Log(("#%d user int\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1260 }
1261 if (pData->aCSR[4] & csr0 & 0x0040 /* CSR_INEA */)
1262 {
1263 csr0 |= 0x0080; /* set INTR */
1264 iISR = 1;
1265 }
1266#else /* !VBOX */
1267 if (!!(pData->aCSR[4] & 0x0080) && CSR_INEA(pData)) /* UINTCMD */
1268 {
1269 pData->aCSR[4] &= ~0x0080;
1270 pData->aCSR[4] |= 0x0040; /* set UINT */
1271 csr0 |= 0x0080; /* set INTR */
1272 iISR = 1;
1273 Log(("#%d user int\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1274 }
1275#endif /* !VBOX */
1276
1277#if 1
1278 if (((pData->aCSR[5]>>1) & pData->aCSR[5]) & 0x0500)
1279#else
1280 if ( (!!(pData->aCSR[5] & 0x0400) && !!(pData->aCSR[5] & 0x0800)) /* SINT */
1281 ||(!!(pData->aCSR[5] & 0x0100) && !!(pData->aCSR[5] & 0x0200)) /* SLPINT */)
1282#endif
1283 {
1284 iISR = 1;
1285 csr0 |= 0x0080; /* INTR */
1286 }
1287
1288 if ((pData->aCSR[7] & 0x0C00) == 0x0C00) /* STINT + STINTE */
1289 iISR = 1;
1290
1291 pData->aCSR[0] = csr0;
1292
1293 Log2(("#%d set irq iISR=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, iISR));
1294
1295 /* normal path is to _not_ change the IRQ status */
1296 if (RT_UNLIKELY(iISR != pData->iISR))
1297 {
1298 Log(("#%d INTA=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, iISR));
1299 PDMDevHlpPCISetIrqNoWait(PCNETSTATE_2_DEVINS(pData), 0, iISR);
1300 pData->iISR = iISR;
1301 }
1302 STAM_PROFILE_ADV_STOP(&pData->StatInterrupt, a);
1303}
1304
1305#ifdef IN_RING3
1306#ifdef PCNET_NO_POLLING
1307static void pcnetUpdateRingHandlers(PCNetState *pData)
1308{
1309 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1310 int rc;
1311
1312 Log(("pcnetUpdateRingHandlers TD %VGp size %#x -> %VGp size %#x\n", pData->TDRAPhysOld, pData->cbTDRAOld, pData->GCTDRA, pcnetTdraAddr(pData, 0)));
1313 Log(("pcnetUpdateRingHandlers RX %VGp size %#x -> %VGp size %#x\n", pData->RDRAPhysOld, pData->cbRDRAOld, pData->GCRDRA, pcnetRdraAddr(pData, 0)));
1314
1315 /** @todo unregister order not correct! */
1316
1317#ifdef PCNET_MONITOR_RECEIVE_RING
1318 if (pData->GCRDRA != pData->RDRAPhysOld || CSR_RCVRL(pData) != pData->cbRDRAOld)
1319 {
1320 if (pData->RDRAPhysOld != 0)
1321 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1322 pData->RDRAPhysOld & ~PAGE_OFFSET_MASK);
1323
1324 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1325 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1326 pData->GCRDRA & ~PAGE_OFFSET_MASK,
1327 RT_ALIGN(pcnetRdraAddr(pData, 0), PAGE_SIZE) - 1,
1328 pcnetHandleRingWrite, pDevIns,
1329 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1330 pData->pDevInsHC->pvInstanceDataHC,
1331 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1332 pData->pDevInsHC->pvInstanceDataGC,
1333 "PCNet receive ring write access handler");
1334 AssertRC(rc);
1335
1336 pData->RDRAPhysOld = pData->GCRDRA;
1337 pData->cbRDRAOld = pcnetRdraAddr(pData, 0);
1338 }
1339#endif /* PCNET_MONITOR_RECEIVE_RING */
1340
1341#ifdef PCNET_MONITOR_RECEIVE_RING
1342 /* 3 possibilities:
1343 * 1) TDRA on different physical page as RDRA
1344 * 2) TDRA completely on same physical page as RDRA
1345 * 3) TDRA & RDRA overlap partly with different physical pages
1346 */
1347 RTGCPHYS32 RDRAPageStart = pData->GCRDRA & ~PAGE_OFFSET_MASK;
1348 RTGCPHYS32 RDRAPageEnd = (pcnetRdraAddr(pData, 0) - 1) & ~PAGE_OFFSET_MASK;
1349 RTGCPHYS32 TDRAPageStart = pData->GCTDRA & ~PAGE_OFFSET_MASK;
1350 RTGCPHYS32 TDRAPageEnd = (pcnetTdraAddr(pData, 0) - 1) & ~PAGE_OFFSET_MASK;
1351
1352 if ( RDRAPageStart > TDRAPageEnd
1353 || TDRAPageStart > RDRAPageEnd)
1354 {
1355#endif /* PCNET_MONITOR_RECEIVE_RING */
1356 /* 1) */
1357 if (pData->GCTDRA != pData->TDRAPhysOld || CSR_XMTRL(pData) != pData->cbTDRAOld)
1358 {
1359 if (pData->TDRAPhysOld != 0)
1360 PGMHandlerPhysicalDeregister(PDMDevHlpGetVM(pDevIns),
1361 pData->TDRAPhysOld & ~PAGE_OFFSET_MASK);
1362
1363 rc = PGMR3HandlerPhysicalRegister(PDMDevHlpGetVM(pDevIns),
1364 PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1365 pData->GCTDRA & ~PAGE_OFFSET_MASK,
1366 RT_ALIGN(pcnetTdraAddr(pData, 0), PAGE_SIZE) - 1,
1367 pcnetHandleRingWrite, pDevIns,
1368 g_DevicePCNet.szR0Mod, "pcnetHandleRingWrite",
1369 pData->pDevInsHC->pvInstanceDataHC,
1370 g_DevicePCNet.szGCMod, "pcnetHandleRingWrite",
1371 pData->pDevInsHC->pvInstanceDataGC,
1372 "PCNet transmit ring write access handler");
1373 AssertRC(rc);
1374
1375 pData->TDRAPhysOld = pData->GCTDRA;
1376 pData->cbTDRAOld = pcnetTdraAddr(pData, 0);
1377 }
1378#ifdef PCNET_MONITOR_RECEIVE_RING
1379 }
1380 else
1381 if ( RDRAPageStart != TDRAPageStart
1382 && ( TDRAPageStart == RDRAPageEnd
1383 || TDRAPageEnd == RDRAPageStart
1384 )
1385 )
1386 {
1387 /* 3) */
1388 AssertFailed();
1389 }
1390 /* else 2) */
1391#endif
1392}
1393#endif /* PCNET_NO_POLLING */
1394
1395static void pcnetInit(PCNetState *pData)
1396{
1397 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1398 Log(("#%d pcnetInit: init_addr=%#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1399 PHYSADDR(pData, CSR_IADR(pData))));
1400
1401 /** @todo Documentation says that RCVRL and XMTRL are stored as two's complement!
1402 * Software is allowed to write these registers directly. */
1403#define PCNET_INIT() do { \
1404 PDMDevHlpPhysRead(pDevIns, PHYSADDR(pData, CSR_IADR(pData)), \
1405 (uint8_t *)&initblk, sizeof(initblk)); \
1406 pData->aCSR[15] = RT_LE2H_U16(initblk.mode); \
1407 CSR_RCVRL(pData) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
1408 CSR_XMTRL(pData) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
1409 pData->aCSR[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
1410 pData->aCSR[ 8] = RT_LE2H_U16(initblk.ladrf1); \
1411 pData->aCSR[ 9] = RT_LE2H_U16(initblk.ladrf2); \
1412 pData->aCSR[10] = RT_LE2H_U16(initblk.ladrf3); \
1413 pData->aCSR[11] = RT_LE2H_U16(initblk.ladrf4); \
1414 pData->aCSR[12] = RT_LE2H_U16(initblk.padr1); \
1415 pData->aCSR[13] = RT_LE2H_U16(initblk.padr2); \
1416 pData->aCSR[14] = RT_LE2H_U16(initblk.padr3); \
1417 pData->GCRDRA = PHYSADDR(pData, initblk.rdra); \
1418 pData->GCTDRA = PHYSADDR(pData, initblk.tdra); \
1419} while (0)
1420
1421 if (BCR_SSIZE32(pData))
1422 {
1423 struct INITBLK32 initblk;
1424 pData->GCUpperPhys = 0;
1425 PCNET_INIT();
1426 Log(("#%d initblk.rlen=%#04x, initblk.tlen=%#04x\n",
1427 PCNETSTATE_2_DEVINS(pData)->iInstance, initblk.rlen, initblk.tlen));
1428 }
1429 else
1430 {
1431 struct INITBLK16 initblk;
1432 pData->GCUpperPhys = (0xff00 & (uint32_t)pData->aCSR[2]) << 16;
1433 PCNET_INIT();
1434 Log(("#%d initblk.rlen=%#04x, initblk.tlen=%#04x\n",
1435 PCNETSTATE_2_DEVINS(pData)->iInstance, initblk.rlen, initblk.tlen));
1436 }
1437
1438#undef PCNET_INIT
1439
1440 if (pData->pDrv)
1441 pData->pDrv->pfnSetPromiscuousMode(pData->pDrv, CSR_PROM(pData));
1442
1443 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1444 CSR_XMTRC(pData) = CSR_XMTRL(pData);
1445
1446#ifdef PCNET_NO_POLLING
1447 pcnetUpdateRingHandlers(pData);
1448#endif
1449
1450 /* Reset cached RX and TX states */
1451 CSR_CRST(pData) = CSR_CRBC(pData) = CSR_NRST(pData) = CSR_NRBC(pData) = 0;
1452 CSR_CXST(pData) = CSR_CXBC(pData) = CSR_NXST(pData) = CSR_NXBC(pData) = 0;
1453
1454 LogRel(("PCNet#%d: Init: ss32=%d GCRDRA=%#010x[%d] GCTDRA=%#010x[%d]\n",
1455 PCNETSTATE_2_DEVINS(pData)->iInstance, BCR_SSIZE32(pData),
1456 pData->GCRDRA, CSR_RCVRL(pData), pData->GCTDRA, CSR_XMTRL(pData)));
1457
1458 pData->aCSR[0] |= 0x0101; /* Initialization done */
1459 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1460}
1461#endif /* IN_RING3 */
1462
1463/**
1464 * Start RX/TX operation.
1465 */
1466static void pcnetStart(PCNetState *pData)
1467{
1468 Log(("#%d pcnetStart:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1469 if (!CSR_DTX(pData))
1470 pData->aCSR[0] |= 0x0010; /* set TXON */
1471 if (!CSR_DRX(pData))
1472 pData->aCSR[0] |= 0x0020; /* set RXON */
1473 pData->aCSR[0] &= ~0x0004; /* clear STOP bit */
1474 pData->aCSR[0] |= 0x0002; /* STRT */
1475}
1476
1477/**
1478 * Stop RX/TX operation.
1479 */
1480static void pcnetStop(PCNetState *pData)
1481{
1482 Log(("#%d pcnetStop:\n", PCNETSTATE_2_DEVINS(pData)->iInstance));
1483 pData->aCSR[0] &= ~0x7feb;
1484 pData->aCSR[0] |= 0x0014;
1485 pData->aCSR[4] &= ~0x02c2;
1486 pData->aCSR[5] &= ~0x0011;
1487 pcnetPollTimer(pData);
1488}
1489
1490#ifdef IN_RING3
1491static DECLCALLBACK(bool) pcnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1492{
1493 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1494 if (pData->pDrv)
1495 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1496 return true;
1497}
1498#endif
1499
1500/**
1501 * Poll Receive Descriptor Table Entry and cache the results in the appropriate registers.
1502 * Note: Once a descriptor belongs to the network card (this driver), it cannot be changed
1503 * by the host (the guest driver) anymore. Well, it could but the results are undefined by
1504 * definition.
1505 * @param fSkipCurrent if true, don't scan the current RDTE.
1506 */
1507static void pcnetRdtePoll(PCNetState *pData, bool fSkipCurrent=false)
1508{
1509 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatRdtePoll), a);
1510 /* assume lack of a next receive descriptor */
1511 CSR_NRST(pData) = 0;
1512
1513 if (RT_LIKELY(pData->GCRDRA))
1514 {
1515 /*
1516 * The current receive message descriptor.
1517 */
1518 RMD rmd;
1519 int i = CSR_RCVRC(pData);
1520 RTGCPHYS32 addr;
1521
1522 if (i < 1)
1523 i = CSR_RCVRL(pData);
1524
1525 if (!fSkipCurrent)
1526 {
1527 addr = pcnetRdraAddr(pData, i);
1528 CSR_CRDA(pData) = CSR_CRBA(pData) = 0;
1529 CSR_CRBC(pData) = CSR_CRST(pData) = 0;
1530 if (!pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr), true))
1531 {
1532 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1533 return;
1534 }
1535 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1536 {
1537 CSR_CRDA(pData) = addr; /* Receive Descriptor Address */
1538 CSR_CRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1539 CSR_CRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1540 CSR_CRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1541#ifdef IN_RING3
1542 if (pData->pDrv)
1543 pData->pDrv->pfnNotifyCanReceive(pData->pDrv);
1544#else
1545 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pCanRxQueue));
1546 if (pItem)
1547 PDMQueueInsert(CTXSUFF(pData->pCanRxQueue), pItem);
1548#endif
1549 }
1550 else
1551 {
1552 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1553 /* This is not problematic since we don't own the descriptor */
1554 LogRel(("PCNet#%d: BAD RMD ENTRIES AT %#010x (i=%d)\n",
1555 PCNETSTATE_2_DEVINS(pData)->iInstance, addr, i));
1556 return;
1557 }
1558 }
1559
1560 /*
1561 * The next descriptor.
1562 */
1563 if (--i < 1)
1564 i = CSR_RCVRL(pData);
1565 addr = pcnetRdraAddr(pData, i);
1566 CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1567 CSR_NRBC(pData) = 0;
1568 if (!pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, addr), true))
1569 {
1570 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1571 return;
1572 }
1573 if (RT_LIKELY(!IS_RMD_BAD(rmd)))
1574 {
1575 CSR_NRDA(pData) = addr; /* Receive Descriptor Address */
1576 CSR_NRBA(pData) = rmd.rmd0.rbadr; /* Receive Buffer Address */
1577 CSR_NRBC(pData) = rmd.rmd1.bcnt; /* Receive Byte Count */
1578 CSR_NRST(pData) = ((uint32_t *)&rmd)[1] >> 16; /* Receive Status */
1579 }
1580 else
1581 {
1582 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1583 /* This is not problematic since we don't own the descriptor */
1584 LogRel(("PCNet#%d: BAD RMD ENTRIES + AT %#010x (i=%d)\n",
1585 PCNETSTATE_2_DEVINS(pData)->iInstance, addr, i));
1586 return;
1587 }
1588
1589 /**
1590 * @todo NNRD
1591 */
1592 }
1593 else
1594 {
1595 CSR_CRDA(pData) = CSR_CRBA(pData) = CSR_NRDA(pData) = CSR_NRBA(pData) = 0;
1596 CSR_CRBC(pData) = CSR_NRBC(pData) = CSR_CRST(pData) = 0;
1597 }
1598 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatRdtePoll), a);
1599}
1600
1601/**
1602 * Poll Transmit Descriptor Table Entry
1603 * @return true if transmit descriptors available
1604 */
1605static int pcnetTdtePoll(PCNetState *pData, TMD *tmd)
1606{
1607 STAM_PROFILE_ADV_START(&pData->CTXSUFF(StatTdtePoll), a);
1608 if (RT_LIKELY(pData->GCTDRA))
1609 {
1610 RTGCPHYS32 cxda = pcnetTdraAddr(pData, CSR_XMTRC(pData));
1611
1612 if (!pcnetTmdLoad(pData, tmd, PHYSADDR(pData, cxda), true))
1613 {
1614 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1615 return 0;
1616 }
1617
1618 if (RT_UNLIKELY(tmd->tmd1.ones != 15))
1619 {
1620 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1621 LogRel(("PCNet#%d: BAD TMD XDA=%#010x\n",
1622 PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, cxda)));
1623 return 0;
1624 }
1625
1626 /* previous xmit descriptor */
1627 CSR_PXDA(pData) = CSR_CXDA(pData);
1628 CSR_PXBC(pData) = CSR_CXBC(pData);
1629 CSR_PXST(pData) = CSR_CXST(pData);
1630
1631 /* set current trasmit decriptor. */
1632 CSR_CXDA(pData) = cxda;
1633 CSR_CXBC(pData) = tmd->tmd1.bcnt;
1634 CSR_CXST(pData) = ((uint32_t *)tmd)[1] >> 16;
1635 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1636 return CARD_IS_OWNER(CSR_CXST(pData));
1637 }
1638 else
1639 {
1640 /** @todo consistency with previous receive descriptor */
1641 CSR_CXDA(pData) = 0;
1642 CSR_CXBC(pData) = CSR_CXST(pData) = 0;
1643 STAM_PROFILE_ADV_STOP(&pData->CTXSUFF(StatTdtePoll), a);
1644 return 0;
1645 }
1646}
1647
1648
1649#ifdef IN_RING3
1650
1651/**
1652 * Check if there is at least one free receive buffer available.
1653 */
1654static int pcnetCanReceiveNoSync(PCNetState *pData)
1655{
1656 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData)))
1657 return 0;
1658
1659 if (HOST_IS_OWNER(CSR_CRST(pData)) && pData->GCRDRA)
1660 pcnetRdtePoll(pData);
1661
1662 if (HOST_IS_OWNER(CSR_CRST(pData)))
1663 {
1664 /** @todo Notify the guest _now_. Will potentially increase the interrupt load */
1665 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1666 return 0;
1667 }
1668
1669 /* byte count stored in two's complement 12 bits wide */
1670 Log(("#%d pcnetCanReceiveNoSync %d bytes\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1671 4096 - CSR_CRBC(pData)));
1672 return 4096 - CSR_CRBC(pData);
1673}
1674
1675/**
1676 * Write data into guest receive buffers.
1677 */
1678static void pcnetReceiveNoSync(PCNetState *pData, const uint8_t *buf, int size)
1679{
1680 PPDMDEVINS pDevIns = PCNETSTATE_2_DEVINS(pData);
1681 int is_padr = 0, is_bcast = 0, is_ladr = 0;
1682 unsigned i;
1683 int pkt_size;
1684
1685 if (RT_UNLIKELY(CSR_DRX(pData) || CSR_STOP(pData) || CSR_SPND(pData) || !size))
1686 return;
1687
1688 Log(("#%d pcnetReceiveNoSync: size=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance, size));
1689
1690 LOG_PACKET("rraw", buf, size);
1691
1692 /*
1693 * Perform address matching.
1694 */
1695 if ( CSR_PROM(pData)
1696 || (is_padr = padr_match(pData, buf, size))
1697 || (is_bcast = padr_bcast(pData, buf, size))
1698 || (is_ladr = ladr_match(pData, buf, size)))
1699 {
1700 if (HOST_IS_OWNER(CSR_CRST(pData)))
1701 pcnetRdtePoll(pData);
1702 if (RT_UNLIKELY(HOST_IS_OWNER(CSR_CRST(pData))))
1703 {
1704 /* Not owned by controller. This should not be possible as
1705 * we already called pcnetCanReceive(). */
1706 LogRel(("PCNet#%d: no buffer: RCVRC=%d\n",
1707 PCNETSTATE_2_DEVINS(pData)->iInstance, CSR_RCVRC(pData)));
1708 /* Dump the status of all RX descriptors */
1709 const unsigned cb = 1 << pData->iLog2DescSize;
1710 RTGCPHYS32 GCPhys = pData->GCRDRA;
1711 i = CSR_RCVRL(pData);
1712 while (i-- > 0)
1713 {
1714 RMD rmd;
1715 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, GCPhys), false);
1716 LogRel((" %#010x\n", rmd.rmd1));
1717 GCPhys += cb;
1718 }
1719 pData->aCSR[0] |= 0x1000; /* Set MISS flag */
1720 CSR_MISSC(pData)++;
1721 }
1722 else
1723 {
1724 uint8_t *src = &pData->abRecvBuf[8];
1725 RTGCPHYS32 crda = CSR_CRDA(pData);
1726 RTGCPHYS32 next_crda;
1727 RMD rmd, next_rmd;
1728 int pktcount = 0;
1729
1730 memcpy(src, buf, size);
1731 if (!CSR_ASTRP_RCV(pData))
1732 {
1733 uint32_t fcs = ~0;
1734 uint8_t *p = src;
1735
1736 while (size < 60)
1737 src[size++] = 0;
1738 while (p != &src[size])
1739 CRC(fcs, *p++);
1740 ((uint32_t *)&src[size])[0] = htonl(fcs);
1741 /* FCS at end of packet */
1742 }
1743 size += 4;
1744 pkt_size = size;
1745
1746#ifdef PCNET_DEBUG_MATCH
1747 PRINT_PKTHDR(buf);
1748#endif
1749
1750 pcnetRmdLoad(pData, &rmd, PHYSADDR(pData, crda), false);
1751 /*if (!CSR_LAPPEN(pData))*/
1752 rmd.rmd1.stp = 1;
1753
1754 int count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1755 RTGCPHYS32 rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1756 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1757 src += count;
1758 size -= count;
1759 pktcount++;
1760
1761 /* Read current receive descriptor index */
1762 i = CSR_RCVRC(pData);
1763
1764 while (size > 0)
1765 {
1766 /* Read the entire next descriptor as we're likely to need it. */
1767 if (--i < 1)
1768 i = CSR_RCVRL(pData);
1769 next_crda = pcnetRdraAddr(pData, i);
1770
1771 /* Check next descriptor's own bit. If we don't own it, we have
1772 * to quit and write error status into the last descriptor we own.
1773 */
1774 if (!pcnetRmdLoad(pData, &next_rmd, PHYSADDR(pData, next_crda), true))
1775 break;
1776
1777 /* Write back current descriptor, clear the own bit. */
1778 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1779
1780 /* Switch to the next descriptor */
1781 crda = next_crda;
1782 rmd = next_rmd;
1783
1784 count = RT_MIN(4096 - (int)rmd.rmd1.bcnt, size);
1785 rbadr = PHYSADDR(pData, rmd.rmd0.rbadr);
1786 PDMDevHlpPhysWrite(pDevIns, rbadr, src, count);
1787 src += count;
1788 size -= count;
1789 pktcount++;
1790 }
1791
1792 if (RT_LIKELY(size == 0))
1793 {
1794 rmd.rmd1.enp = 1;
1795 rmd.rmd1.pam = !CSR_PROM(pData) && is_padr;
1796 rmd.rmd1.lafm = !CSR_PROM(pData) && is_ladr;
1797 rmd.rmd1.bam = !CSR_PROM(pData) && is_bcast;
1798 rmd.rmd2.mcnt = pkt_size;
1799
1800 STAM_REL_COUNTER_ADD(&pData->StatReceiveBytes, pkt_size);
1801 }
1802 else
1803 {
1804 LogRel(("PCNet#%d: Overflow by %ubytes\n",
1805 PCNETSTATE_2_DEVINS(pData)->iInstance, size));
1806 rmd.rmd1.oflo = 1;
1807 rmd.rmd1.buff = 1;
1808 rmd.rmd1.err = 1;
1809 }
1810
1811 /* write back, clear the own bit */
1812 pcnetRmdStorePassHost(pData, &rmd, PHYSADDR(pData, crda));
1813
1814 pData->aCSR[0] |= 0x0400;
1815
1816 Log(("#%d RCVRC=%d CRDA=%#010x BLKS=%d\n", PCNETSTATE_2_DEVINS(pData)->iInstance,
1817 CSR_RCVRC(pData), PHYSADDR(pData, CSR_CRDA(pData)), pktcount));
1818#ifdef PCNET_DEBUG_RMD
1819 PRINT_RMD(&rmd);
1820#endif
1821
1822 while (pktcount--)
1823 {
1824 if (CSR_RCVRC(pData) < 2)
1825 CSR_RCVRC(pData) = CSR_RCVRL(pData);
1826 else
1827 CSR_RCVRC(pData)--;
1828 }
1829 /* guest driver is owner: force repoll of current and next RDTEs */
1830 CSR_CRST(pData) = 0;
1831 }
1832 }
1833
1834 /* see description of TXDPOLL:
1835 * ``transmit polling will take place following receive activities'' */
1836 pcnetPollRxTx(pData);
1837 pcnetUpdateIrq(pData);
1838}
1839
1840
1841/**
1842 * Checks if the link is up.
1843 * @returns true if the link is up.
1844 * @returns false if the link is down.
1845 */
1846DECLINLINE(bool) pcnetIsLinkUp(PCNetState *pData)
1847{
1848 return pData->pDrv && !pData->fLinkTempDown && pData->fLinkUp;
1849}
1850
1851
1852/**
1853 * Transmit queue consumer
1854 * This is just a very simple way of delaying sending to R3.
1855 *
1856 * @returns Success indicator.
1857 * If false the item will not be removed and the flushing will stop.
1858 * @param pDevIns The device instance.
1859 * @param pItem The item to consume. Upon return this item will be freed.
1860 */
1861static DECLCALLBACK(bool) pcnetXmitQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
1862{
1863 PCNetState *pData = PDMINS2DATA(pDevIns, PCNetState *);
1864 NOREF(pItem);
1865
1866 /* Clear counter .*/
1867 ASMAtomicAndU32(&pData->cPendingSends, 0);
1868#ifdef PCNET_QUEUE_SEND_PACKETS
1869 pcnetSyncTransmit(pData);
1870#else
1871 int rc = RTSemEventSignal(pData->hSendEventSem);
1872 AssertRC(rc);
1873#endif
1874 return true;
1875}
1876
1877
1878/**
1879 * Scraps the top frame.
1880 * This is done as a precaution against mess left over by on
1881 */
1882DECLINLINE(void) pcnetXmitScrapFrame(PCNetState *pData)
1883{
1884 pData->SendFrame.pvBuf = NULL;
1885 pData->SendFrame.cb = -1;
1886}
1887
1888
1889/**
1890 * If we are in RING3 don't copy the frame from GC here but only store the address. We
1891 * don't need to buffer the frames because a direct address translation was possible.
1892 */
1893DECLINLINE(void) pcnetXmitZeroCopyFrame(PCNetState *pData, RTR3PTR pv, const unsigned cbFrame)
1894{
1895 pData->SendFrame.pvBuf = pv;
1896 pData->SendFrame.cb = cbFrame;
1897}
1898
1899
1900/**
1901 * Reads the first part of a frame
1902 */
1903DECLINLINE(void) pcnetXmitRead1st(PCNetState *pData, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
1904{
1905 Assert(cbFrame < sizeof(pData->abSendBuf));
1906
1907 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame, &pData->abSendBuf[0], cbFrame);
1908 pData->SendFrame.pvBuf = pData->abSendBuf;
1909 pData->SendFrame.cb = cbFrame;
1910}
1911
1912
1913/**
1914 * Reads more into the current frame.
1915 */
1916DECLINLINE(void) pcnetXmitReadMore(PCNetState *pData, RTGCPHYS32 GCPhysFrame, const unsigned cbFrame)
1917{
1918 Assert(pData->SendFrame.cb + cbFrame < sizeof(pData->abSendBuf));
1919 PDMDevHlpPhysRead(pData->CTXSUFF(pDevIns), GCPhysFrame, &pData->abSendBuf[pData->SendFrame.cb], cbFrame);
1920 pData->SendFrame.cb += cbFrame;
1921}
1922
1923
1924/**
1925 * Completes the current frame.
1926 * If we've reached the maxium number of frames, they will be flushed.
1927 */
1928DECLINLINE(int) pcnetXmitCompleteFrame(PCNetState *pData)
1929{
1930#ifdef PCNET_QUEUE_SEND_PACKETS
1931 Assert(!pData->cbXmitRingBuffer[pData->ulXmitRingBufProd]);
1932 memcpy(pData->pXmitRingBuffer[pData->ulXmitRingBufProd], pData->SendFrame.pvBuf, pData->SendFrame.cb);
1933 pData->cbXmitRingBuffer[pData->ulXmitRingBufProd] = (uint16_t)pData->SendFrame.cb;
1934 pData->ulXmitRingBufProd = (pData->ulXmitRingBufProd+1) & PCNET_MAX_XMIT_SLOTS_MASK;
1935
1936 int rc = RTSemEventSignal(pData->hSendEventSem);
1937 AssertRC(rc);
1938
1939 return VINF_SUCCESS;
1940#else
1941 /* Don't hold the critical section while transmitting data. */
1942 /** @note also avoids deadlocks with NAT as it can call us right back. */
1943 PDMCritSectLeave(&pData->CritSect);
1944
1945 STAM_PROFILE_ADV_START(&pData->StatTransmitSend, a);
1946 if (pData->SendFrame.cb > 70) /* unqualified guess */
1947 pData->Led.Asserted.s.fWriting = pData->Led.Actual.s.fWriting = 1;
1948
1949 pData->pDrv->pfnSend(pData->pDrv, pData->SendFrame.pvBuf, pData->SendFrame.cb);
1950 STAM_REL_COUNTER_ADD(&pData->StatTransmitBytes, pData->SendFrame.cb);
1951 pData->Led.Actual.s.fWriting = 0;
1952 STAM_PROFILE_ADV_STOP(&pData->StatTransmitSend, a);
1953
1954 return PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
1955#endif
1956}
1957
1958
1959/**
1960 * Fails a TMD with a link down error.
1961 */
1962static void pcnetXmitFailTMDLinkDown(PCNetState *pData, TMD *pTmd)
1963{
1964 /* make carrier error - hope this is correct. */
1965 pData->cLinkDownReported++;
1966 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1967 pData->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR */
1968 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1969 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1970 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1971}
1972
1973/**
1974 * Fails a TMD with a generic error.
1975 */
1976static void pcnetXmitFailTMDGeneric(PCNetState *pData, TMD *pTmd)
1977{
1978 /* make carrier error - hope this is correct. */
1979 pTmd->tmd2.lcar = pTmd->tmd1.err = 1;
1980 pData->aCSR[0] |= RT_BIT(15) | RT_BIT(13); /* ERR | CERR */
1981 pData->Led.Asserted.s.fError = pData->Led.Actual.s.fError = 1;
1982 Log(("#%d pcnetTransmit: Signaling send error. swstyle=%#x\n",
1983 PCNETSTATE_2_DEVINS(pData)->iInstance, pData->aBCR[BCR_SWS]));
1984}
1985
1986
1987/**
1988 * Transmit a loopback frame.
1989 */
1990DECLINLINE(void) pcnetXmitLoopbackFrame(PCNetState *pData)
1991{
1992 pData->Led.Asserted.s.fReading = pData->Led.Actual.s.fReading = 1;
1993 if (HOST_IS_OWNER(CSR_CRST(pData)))
1994 pcnetRdtePoll(pData);
1995
1996 Assert(pData->SendFrame.pvBuf);
1997 pcnetReceiveNoSync(pData, (const uint8_t *)pData->SendFrame.pvBuf, pData->SendFrame.cb);
1998 pcnetXmitScrapFrame(pData);
1999 pData->Led.Actual.s.fReading = 0;
2000}
2001
2002/**
2003 * Flushes queued frames.
2004 */
2005DECLINLINE(void) pcnetXmitFlushFrames(PCNetState *pData)
2006{
2007 pcnetXmitQueueConsumer(CTXSUFF(pData->pDevIns), NULL);
2008}
2009
2010#endif /* IN_RING3 */
2011
2012
2013
2014/**
2015 * Try to transmit frames
2016 */
2017static void pcnetTransmit(PCNetState *pData)
2018{
2019 if (RT_UNLIKELY(!CSR_TXON(pData)))
2020 {
2021 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
2022 return;
2023 }
2024
2025 /*
2026 * Check the current transmit descriptors.
2027 */
2028 TMD tmd;
2029 if (!pcnetTdtePoll(pData, &tmd))
2030 return;
2031
2032 /* Update TDMD, TXSTRT and TINT. */
2033 pData->aCSR[0] &= ~0x0008; /* clear TDMD */
2034
2035 /*
2036 * If we're in Ring-3 we should flush the queue now, in GC/R0 we'll queue a flush job.
2037 */
2038#ifdef IN_RING3
2039 pcnetXmitFlushFrames(pData);
2040#else
2041# if 1
2042 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
2043 if (RT_UNLIKELY(pItem))
2044 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
2045# else
2046 if (ASMAtomicIncU32(&pData->cPendingSends) < 16)
2047 {
2048 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(CTXSUFF(pData->pXmitQueue));
2049 if (RT_UNLIKELY(pItem))
2050 PDMQueueInsert(CTXSUFF(pData->pXmitQueue), pItem);
2051 }
2052 else
2053 PDMQueueFlush(CTXSUFF(pData->pXmitQueue));
2054# endif
2055#endif
2056}
2057
2058#ifdef IN_RING3
2059
2060/**
2061 * Try to transmit frames
2062 */
2063#ifdef PCNET_QUEUE_SEND_PACKETS
2064static int pcnetAsyncTransmit(PCNetState *pData)
2065{
2066 Assert(PDMCritSectIsOwner(&pData->CritSect));
2067
2068 while (pData->cbXmitRingBuffer[pData->ulXmitRingBufCons])
2069 {
2070 /* Don't hold the critical section while transmitting data. */
2071 /** @note also avoids deadlocks with NAT as it can call us right back. */
2072 PDMCritSectLeave(&pData->CritSect);
2073
2074 STAM_PROFILE_ADV_START(&pData->StatTransmitSend, a);
2075 if (pData->SendFrame.cb > 70) /* unqualified guess */
2076 pData->Led.Asserted.s.fWriting = pData->Led.Actual.s.fWriting = 1;
2077
2078 pData->pDrv->pfnSend(pData->pDrv, pData->pXmitRingBuffer[pData->ulXmitRingBufCons], pData->cbXmitRingBuffer[pData->ulXmitRingBufCons]);
2079 STAM_REL_COUNTER_ADD(&pData->StatTransmitBytes, pData->cbXmitRingBuffer[pData->ulXmitRingBufCons]);
2080 pData->Led.Actual.s.fWriting = 0;
2081 STAM_PROFILE_ADV_STOP(&pData->StatTransmitSend, a);
2082
2083 PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
2084
2085 pData->cbXmitRingBuffer[pData->ulXmitRingBufCons] = 0;
2086 pData->ulXmitRingBufCons = (pData->ulXmitRingBufCons+1) & PCNET_MAX_XMIT_SLOTS_MASK;
2087 }
2088 return VINF_SUCCESS;
2089}
2090
2091static int pcnetSyncTransmit(PCNetState *pData)
2092#else
2093static int pcnetAsyncTransmit(PCNetState *pData)
2094#endif
2095{
2096 unsigned cFlushIrq = 0;
2097
2098 Assert(PDMCritSectIsOwner(&pData->CritSect));
2099
2100 if (RT_UNLIKELY(!CSR_TXON(pData)))
2101 {
2102 pData->aCSR[0] &= ~0x0008; /* Clear TDMD */
2103 return VINF_SUCCESS;
2104 }
2105
2106 /*
2107 * Iterate the transmit descriptors.
2108 */
2109 STAM_PROFILE_ADV_START(&pData->StatTransmit, a);
2110 do
2111 {
2112#ifdef VBOX_WITH_STATISTICS
2113 unsigned cBuffers = 1;
2114#endif
2115 TMD tmd;
2116 if (!pcnetTdtePoll(pData, &tmd))
2117 break;
2118
2119 /* Don't continue sending packets when the link is down. */
2120 if (RT_UNLIKELY( !pcnetIsLinkUp(pData)
2121 && pData->cLinkDownReported > PCNET_MAX_LINKDOWN_REPORTED)
2122 )
2123 break;
2124
2125#ifdef PCNET_DEBUG_TMD
2126 Log2(("#%d TMDLOAD %#010x\n", PCNETSTATE_2_DEVINS(pData)->iInstance, PHYSADDR(pData, CSR_CXDA(pData))));
2127 PRINT_TMD(&tmd);
2128#endif
2129 pcnetXmitScrapFrame(pData);
2130
2131 /*
2132 * The typical case - a complete packet.
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_TX");
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/UpdateIRQ", 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