VirtualBox

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

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

Wrong sample names

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette