VirtualBox

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

Last change on this file since 810 was 810, checked in by vboxsync, 18 years ago

Paranoid own bit checks in TMD & RMD reads.

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