VirtualBox

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

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

Corrected link restoration again

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