VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevDP8390.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 197.0 KB
Line 
1/* $Id: DevDP8390.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * DevDP8390 - National Semiconductor DP8390-based Ethernet Adapter Emulation.
4 */
5
6/*
7 * Copyright (C) 2022-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_dev_dp8390 NatSemi DP8390-Based Ethernet NIC Emulation.
29 *
30 * This software was written based on the following documents:
31 *
32 * - National Semiconductor DP8390/NS32490 Network Interface Controller,
33 * 1986
34 * - National Semiconductor DP8390D/NS32490D NIC Network Interface
35 * Controller datasheet, July 1995
36 * - National Semiconductor Application Note 729, DP839EB-ATN IBM PC-AT
37 * Compatible DP83901 SNIC Serial Network Interface Controller
38 * Evaluation Board, 1993
39 * - National Semiconductor Application Note 842, The Design and Operation
40 * of a Low Cost, 8-Bit PC-XT Compatible Ethernet Adapter Using
41 * the DP83902, May 1993
42 * - National Semiconductor Application Note 858, Guide to Loopback Using
43 * the DP8390 Chip Set, October 1992
44 * - National Semiconductor Application Note 875, DP83905EB-AT AT/LANTIC
45 * Evaluation Board, June 1993
46 * - Western Digital WD83C584 Bus Interface Controller Device datasheet,
47 * October 29, 1990
48 * - Western Digital WD83C690 Ethernet LAN Controller datasheet,
49 * November 2, 1990
50 * - 3Com EtherLink II Adapter Technical Reference Manual,
51 * March 1991
52 *
53 * This emulation is compatible with drivers for:
54 * - Novell/Eagle/Anthem NE1000 (8-bit)
55 * - Novell/Eagle/Anthem NE2000 (16-bit)
56 * - Western Digital/SMC WD8003E (8-bit)
57 * - Western Digital/SMC WD8013EBT (16-bit)
58 * - 3Com EtherLink II 3C503 (8-bit)
59 *
60 *
61 * The National Semiconductor DP8390 was an early (circa 1986) low-cost
62 * Ethernet controller, typically accompanied by the DP8391 Serial Network
63 * Interface and the DP8392 Coaxial Transceiver Interface.
64 *
65 * Due to its relatively low cost, the DP8390 NIC was chosen for several
66 * very widespread early PC Ethernet designs, namely the Novell NE1000/NE2000,
67 * Western Digital (later SMC) WD8003 EtherCard Plus, and 3Com EtherLink II.
68 * The popularity of these cards, especially the NE2000, in turn spawned
69 * a bevy of compatible chips from National Semiconductor and many others.
70 *
71 * All common DP8390-based cards have onboard memory. The initial WD8003E and
72 * NE1000 cards have one 8Kx8 SRAM; 16-bit cards like WD8013E or NE2000 have
73 * two 8Kx8 SRAMs wired in 8Kx16 configuration to enable 16-bit wide transfers.
74 * The DP8390 can address up to 64K or local memory and uses "Local DMA"
75 * (similar to bus mastering) to access it. Some newer cards had 32K or more
76 * onboard RAM. Note that an NE2000 in 8-bit mode can only address 8K local
77 * memory, effectively reverting to an NE1000.
78 *
79 * The DP8390 uses "Remote DMA" to move data between local memory and the host
80 * system. Remote DMA is quite similar to 8237-style third party DMA, except
81 * the DMA controller is on the DP8390 chip in this case.
82 *
83 * The DP8390 has a control bit (DCR.WTS) which selects whether all DMA (both
84 * Local and Remote) transfers are 8-bit or 16-bit. Word-wide transfers can
85 * generally only be used on a 16-bit card in a 16-bit slot, because only then
86 * can the host drive 16-bit I/O cycles to the data ports. That is why
87 * an NE2000 in an 8-bit slot can only use half of its local RAM -- remote DMA
88 * simply cannot access half of the 8Kx16 SRAM.
89 *
90 * The DP8390 maps its internal registers as sixteen 8-bit wide I/O ports.
91 * There are four register pages, selectable through the Command Register (CR)
92 * which is accessible at offset 0 in all pages.
93 *
94 * The NE1000/NE2000 cards only use I/O and IRQ resources, not memory
95 * or DMA. In contrast, the Western Digital cards use memory-mapped buffers.
96 * Later AT/LANTIC (DP83905) based NE2000-compatible cards can optionally
97 * use memory as well. The 3Com EtherLink II (3C503) uses a custom gate array
98 * in addition to the DP8390 and can use programmed I/O, 8237 DMA, as well
99 * as optional direct memory mapping.
100 *
101 * Address decoding is typically incomplete, which causes the buffer RAM and
102 * possibly PROM to be aliased multiple times in the DP8390's address space.
103 *
104 * Buffer overflow handling is slightly tricky. The DP8390 assumes that if
105 * the receiver is enabled, there is space for at least one page (256 bytes).
106 * Once it fills up the page and advances the CURR pointer, the DP8390 checks
107 * whether CURR equals BNRY and if so, triggers an overflow condition. Note
108 * that after the NIC is initialized, CURR *will* normally equal BNRY, with
109 * both pointing at the beginning of the receive ring (PSTART). An overflow
110 * is only triggered when CURR equals BNRY right after advancing.
111 *
112 * The documentation of the Send Packet command mentions that when CRDA crosses
113 * the PSTOP register, the current remote DMA address (i.e. CRDA) is set to
114 * the PSTART value, which is rather convenient when reading received packets
115 * out of the ring buffer using remote DMA. The documentation does not mention
116 * that the same logic applies for all remote DMA reads, a feature that several
117 * NE1000/NE2000 drivers (packet drivers, Novell ODI) rely on. This is logical,
118 * because reading out of the receive ring buffer address range always implies
119 * reading received packets, and then the PSTOP->PSTART wraparound becomes
120 * desirable. It is unclear whether the same wraparound handling also applies
121 * for remote DMA writes within the receive ring buffer.
122 *
123 * The documentation is not very clear on how the CRDA register is managed.
124 * One might be led to believe that starting remote DMA copies the remote DMA
125 * start address (i.e. RSAR) to the CRDA register. However, the NE1000 ODI
126 * driver for OS/2 1.0 (NE1000.SYS from early 1988) relies on restarting remote
127 * DMA and continuing where it left off. The DP8390D datasheet only mentions
128 * this in a passing fashion at the end of the "Remote Write with High Speed
129 * Buses" section, saying that if a dummy remote read is executed before a
130 * remote write, RSAR can be set up for the dummy read such that the CRDA
131 * register contains the desired value for the following write.
132 *
133 * Conversely, it is not spelled out that writing RSAR also updates CRDA, but
134 * at least Novell's NE2000 ODI driver v2.12 is known to rely on this behavior
135 * and checks that a write to RSAR is reflected in CRDA.
136 *
137 * Loopback operation is limited in the DP8390. Because it is a half-duplex
138 * device, it cannot truly transmit and receive simultaneously. When loopback
139 * is in effect, the received data is *not* written into memory. Only the last
140 * few bytes of the packet are visible in the FIFO.
141 *
142 * Likewise due to its half-duplex nature, the CRC circuitry during loopback
143 * works either only on the transmit side (FCS is generated but not checked)
144 * or the receive side (FCS is checked but not generated).
145 *
146 * The loopback behavior is even stranger when DCR.WTS is set to enabled 16-bit
147 * DMA transfers. Even though the chip reads 16 bits at a time, only 8 bits are
148 * actually transmitted; the DCR.BOS bit determines whether the low or high
149 * 8 bits of each words are transmitted. As a consequence, the programmed length
150 * of the transmit is also halved.
151 *
152 * Because loopback operation is so different from normal send/receive, loopback
153 * packets are not run through the normal receive path and are treated specially
154 * instead. The WD and especially 3C503 diagnostics exercise the loopback
155 * functionality fairly thoroughly.
156 *
157 *
158 * NE1000 and NE2000
159 * -----------------
160 *
161 * Common NE1000/NE2000 configurations in Novell drivers:
162 * I/O Base = 300h, IRQ = 3 (default)
163 * I/O Base = 320h, IRQ = 2
164 * I/O Base = 340h, IRQ = 4
165 * I/O Base = 360h, IRQ = 5
166 * The I/O base can be set to 300h/320h/340h/360h; the IRQ to 2, 3, 4, 5.
167 * No memory or DMA is used.
168 *
169 * The NE1000/NE2000 adds a data register and a reset register to the I/O
170 * space. A PROM containing the node address is mapped into the DP8390's local
171 * address space.
172 *
173 * The mapping of the 32x8 PROM on an NE2000 card is quite non-obvious but
174 * fortunately well explained in the AN-729 Application Note. Address lines
175 * A4-A1 of the internal bus are connected to lines A3-A0 of the PROM
176 * (enabling 16 distinct bytes of the 32-byte PROM to be addressed). However,
177 * the negated EN16 signal, which is active when the NE2000 is in a 16-bit
178 * slot, is connected to the PROM's address line A4. That means an NE2000 in
179 * a 16-bit slot reads different PROM bytes than when the same card is in an
180 * 8-bit slot. The PROM is structured such that an NE2000 in an 8-bit slot
181 * reads a 'BB' signature (same as NE1000) at PROM offset 1Eh/1Fh, while
182 * an NE2000 in a 16-bit slot returns a 'WW' signature from PROM offset
183 * 0Eh/0Fh instead.
184 *
185 * The original NE1000 boards Assy. #950-054401 actually only had 6 bytes of
186 * MAC address in the PROM, the rest was unused (0FFh). Software supporting the
187 * NE1000 thus should not examine the PROM contents beyond the first 6 bytes.
188 *
189 * Novell's old OUI was 00:00:D8 but drivers are not known to check for it.
190 *
191 * Newer DP83905 AT/LANTIC based NE2000plus cards were optionally capable of
192 * using shared RAM in a manner very similar to the WD8003/WD8013.
193 *
194 *
195 * WD8003 and WD8013 EtherCard Plus
196 * --------------------------------
197 *
198 * Common WD8013 configurations:
199 * I/O Base = 280h, IRQ = 3, RAM D000-D3FF (default)
200 * I/O Base = 330h, IRQ = 10, RAM CC00-CFFF
201 * I/O Base = 240h, IRQ/RAM soft-configurable
202 * The I/O base can be set anywhere in the 2xxh-3xxh range in 20h increments.
203 * The IRQs available on a WD8013 are 2, 3, 4, 5, 7, 10, 11, 15. The shared
204 * RAM can be anywhere between 80000h (512K) to FFC000h (16M-16K) in 16K
205 * increments.
206 *
207 * The Western Digital WD8003E appeared at around the same time as Novell's
208 * NE1000 (1987). It is likewise a short 8-bit ISA card with 8Kx8 onboard
209 * SRAM. The major difference is that rather than using remote DMA to move
210 * data between the host and local RAM, the WD8003 directly mapps the onboard
211 * memory to the host's address space (often called shared memory). A later
212 * 16-bit WD8013 model used 8Kx16 SRAM, and there were follow-on WD8003 models
213 * with 16K or 32K local RAM.
214 *
215 * Instead of mapping the PROM into the DP8390's local address space, the
216 * WD8003/WD8013 exposes the node address through the I/O space; the DP8390's
217 * local address space only contains buffer RAM.
218 *
219 * The WD8003 cannot use remote DMA at all; the host must use shared memory.
220 * Remote DMA can be programmed but there is no way to trigger RDMA transfers.
221 *
222 * Western Digital's brand name for WD8003/WD8013 was EtherCard. Circa 1991,
223 * WD sold the networking business to SMC; SMC continued to sell and further
224 * develop the cards under the Elite brand name, also designated as the
225 * SMC8000 series.
226 *
227 * The original WD8003E/EBT/WT uses very simple glue logic around the DP8390
228 * and must be configured through jumpers. Newer WD8003EB/EP/EW/W/WC uses an
229 * interface chip (WD83C583, WD83C584, or later) with an EEPROM and can be
230 * configured through a software utility.
231 *
232 * Similarly the 16-bit WD8013EBT is configured only though jumpers, while
233 * the newer WD8013EB/W/EW/EWC/WC/EPC are software configurable.
234 *
235 * The "Board ID" byte (at offset 6 in the PROM) is used to distinguish
236 * between the various models.
237 *
238 * Newer WD cards use the WD83C690 controller rather than DP8390. The
239 * WD83C690 is close enough to DP8390 that old WD drivers should work with
240 * it, but it has a number of differences. It has no support for Remote DMA
241 * whatsoever, and does not implement multicast filtering.
242 *
243 * The WD83C690 also handles receive buffer overflows somewhat differently;
244 * the DP8390 never fills the last remaining buffer page, meaning that
245 * CURR=BNRY indicates an empty buffer while CURR=BNRY-1 means buffer full.
246 * The WD83C690 can fill all pages and decides whether it is full or empty
247 * based on whether CURR or BNRY was changed more recently.
248 *
249 * Old Western Digital utilities/drivers may require the card to have WD's
250 * old OUI of 00:00:0C and refuse to recognize the hardware otherwise.
251 *
252 * The emulation passes WD diagnostics with no errors (DIAGNOSE.EXE Ver 1.11,
253 * dated 12/12/1989).
254 *
255 *
256 * 3C503 EtherLink II
257 * ------------------
258 *
259 * Common 3C503 configurations in Novell drivers:
260 * I/O Base = 300h, IRQ = 3 (default)
261 * The I/O base can be set via jumpers to 2E0h, 2A0h, 280h, 250h, 350h, 330h,
262 * 310h, or 300h (default). The ROM/RAM can be optionally mapped to one of
263 * DC000-DFFFF, D8000-DBFFF, CC000-CFFFF, or C8000-CBFFF, again configured
264 * through jumpers. The available IRQs are 2, 3, 4, or 5, and DRQs 1, 2, or 3,
265 * both soft-configurable (no IRQ/DRQ jumpers).
266 *
267 * Yet another design based on the DP8390 was the 3Com 3C503 EtherLink II,
268 * available sometime in 1988. Unlike Novell and WD, 3Com added a custom
269 * host interface ASIC ("Gate Array") which handles all transfers to and from
270 * the 8Kx8 onboard SRAM. The 3C503 can map the card's local RAM directly
271 * into the host's address space, alternatively software can use either PIO
272 * or 8-bit DMA to transfer data.
273 *
274 * For reasons that are not entirely clear, 3Com decided that the Remote DMA
275 * implementation on the DP3890 (successfully used by the NE1000/NE2000) was
276 * too buggy and the Gate Array essentially duplicates the Remote DMA
277 * functionality, while also adding 8327 style DMA support (like the DP839EB
278 * had) and optional shared RAM.
279 *
280 * Just like the NE1000/NE2000 and WD8003/WD8013, the 3C503 exists in an
281 * 8-bit variant (EtherLink II) and a 16-bit variant (EtherLink II/16),
282 * although both types are called 3C503.
283 *
284 * Since the 3C503 does not require shared RAM to operate, 3Com decided to
285 * use a single memory mapping for both a boot ROM (if present) and shared
286 * RAM. It is possible to boot from the ROM utilizing PIO or DMA for data
287 * transfers, and later switch to shared RAM. However, 3Com needed to add
288 * a hack for warm boot; the Vector Pointer Registers (VPTR0/1/2) contain
289 * a 20-bit address and the Gate Array monitors the ISA bus for a read cycle
290 * to that address. When a read cycle from the VPTR address occurs, the
291 * memory mapping is switched from RAM to ROM. The VPTR registers are meant
292 * to be programmed with the warm boot vector (often F000:FFF0 or FFFF0h).
293 *
294 * Some UNIX 3C503 drivers may require the card to have 3Com's old OUI
295 * of 02:60:8C and refuse to detect the hardware otherwise. Likewise the
296 * 3C503 diagnostics fail if the OUI is not 3Com's.
297 *
298 * The emulation passes 3Com diagnostics with flying colors (3C503.EXE Version
299 * 1.5, dated 11/26/1991).
300 *
301 *
302 * Linux Drivers
303 *
304 * The DP8390 driver (shared by NE1000/NE2000, WD8003/WD8013, and 3C503 drivers)
305 * in Linux has severe bugs in the receive path. The driver clears receive
306 * interrupts *after* going through the receive ring; that causes it to race
307 * against the DP8390 chip and sometimes dismiss receive interrupts without
308 * handling them. The driver also only receives at most 9 packets at a time,
309 * which again can cause already received packets to be "hanging" in the receive
310 * queue without the driver processing them.
311 * In addition, prior to Linux 1.3.47, the driver incorrectly cleared the
312 * overflow warning interrupt after any receive, causing it to potentially
313 * miss overflow interrupts.
314 *
315 * The above bugs cause received packets to be lost or retransmitted by sender,
316 * causing major TCP/IP performance issues when the DP8390 receives packets
317 * very quickly. Other operating systems do not exhibit these bugs.
318 *
319 *
320 * BSD Drivers
321 *
322 * For reasons that are not obvious, BSD drivers have configuration defaults far
323 * off from the hardware defaults. For NE2000 (ne1), it is I/O base 300h and
324 * IRQ 10. For WD8003E (we0), it is I/O base 280h, IRQ 9, memory D0000-D1FFF.
325 * For 3C503 (ec0), it is I/O base 250h, IRQ 9, memory D8000-D9FFF (no DMA).
326 *
327 * The resource assigments are difficult to configure (sometimes impossible on
328 * installation CDs) and the high IRQs may clash with PCI devices.
329 *
330 */
331
332
333/*********************************************************************************************************************************
334* Header Files *
335*********************************************************************************************************************************/
336#define LOG_GROUP LOG_GROUP_DEV_DP8390
337#include <VBox/vmm/pdmdev.h>
338#include <VBox/vmm/pdmnetifs.h>
339#include <VBox/vmm/pgm.h>
340#include <VBox/version.h>
341#include <iprt/asm.h>
342#include <iprt/assert.h>
343#include <iprt/critsect.h>
344#include <iprt/net.h>
345#include <iprt/string.h>
346#include <iprt/time.h>
347#ifdef IN_RING3
348# include <iprt/mem.h>
349# include <iprt/semaphore.h>
350# include <iprt/uuid.h>
351#endif
352
353#include "VBoxDD.h"
354
355
356/*********************************************************************************************************************************
357* Defined Constants And Macros *
358*********************************************************************************************************************************/
359
360#define DPNIC_SAVEDSTATE_VERSION 1
361
362/** Maximum number of times we report a link down to the guest (failure to send frame) */
363#define DPNIC_MAX_LINKDOWN_REPORTED 3
364
365/** Maximum number of times we postpone restoring a link that is temporarily down. */
366#define DPNIC_MAX_LINKRST_POSTPONED 3
367
368/** Maximum frame size we handle */
369#define MAX_FRAME 1536
370
371/* Size of the local RAM. */
372#define DPNIC_MEM_SIZE 16384u
373
374#define DPNIC_MEM_MASK (DPNIC_MEM_SIZE - 1)
375
376/* Although it is a 16-bit adapter, the EtherLink II only supports 8-bit DMA
377 * and therefore DMA channels 1 to 3 are available.
378 */
379#define ELNKII_MIN_VALID_DMA 1
380#define ELNKII_MAX_VALID_DMA 3
381
382/* EtherLink II Gate Array revision. */
383#define ELNKII_GA_REV 1
384
385
386/*********************************************************************************************************************************
387* Structures and Typedefs *
388*********************************************************************************************************************************/
389
390
391/**
392 * Emulated device types.
393 */
394enum DP8390_DEVICE_TYPE
395{
396 DEV_NE1000 = 0, /* Novell NE1000 compatible (8-bit). */
397 DEV_NE2000 = 1, /* Novell NE2000 compatible (16-bit). */
398 DEV_WD8003 = 2, /* Western Digital WD8003 EtherCard Plus compatible (8-bit). */
399 DEV_WD8013 = 3, /* Western Digital WD8013 EtherCard Plus compatible (16-bit). */
400 DEV_3C503 = 4 /* 3Com 3C503 EtherLink II compatible. */
401};
402
403/** WD8003/WD80013 specific register offsets. */
404#define WDR_CTRL1 0 /* Control register 1. */
405#define WDR_ATDET 1 /* 16-bit slot detect. */
406#define WDR_IOBASE 2 /* I/O base register. */
407#define WDR_CTRL2 5 /* Control register 2. */
408#define WDR_JP 6 /* Jumper settings. */
409#define WDR_PROM 8 /* PROM offset in I/O space. */
410
411/** WD8013 Control Register 1. */
412typedef struct WD_CTRL1 {
413 uint8_t A13_18 : 6; /* Shared memory decoding A13-A18. */
414 uint8_t MEME : 1; /* Enable memory access. */
415 uint8_t RESET : 1; /* Reset NIC core. */
416} WD_CTRL1;
417AssertCompile(sizeof(WD_CTRL1) == sizeof(uint8_t));
418
419/** WD8013 Control Register 2. */
420typedef struct WD_CTRL2 {
421 uint8_t A19_23 : 5; /* Shared memory decoding A19-A23. */
422 uint8_t res : 1; /* Reserved. */
423 uint8_t MEMW : 1; /* Memory width (16-bit wide if set). */
424 uint8_t M16 : 1; /* Allow 16-bit host memory cycles if set. */
425} WD_CTRL2;
426AssertCompile(sizeof(WD_CTRL2) == sizeof(uint8_t));
427
428
429/** 3C503 EtherLink II specific register offsets. */
430#define GAR_PSTR 0
431#define GAR_PSPR 1
432#define GAR_DQTR 2
433#define GAR_R_BCFR 3
434#define GAR_R_PCFR 4
435#define GAR_GACFR 5
436#define GAR_GACR 6
437#define GAR_STREG 7
438#define GAR_IDCFR 8
439#define GAR_DAMSB 9
440#define GAR_DALSB 10
441#define GAR_VPTR2 11
442#define GAR_VPTR1 12
443#define GAR_VPTR0 13
444#define GAR_RFMSB 14
445#define GAR_RFLSB 15
446
447/** 3C503 EtherLink II Gate Array registers. */
448
449/** Gate Array DRQ Timer Register. */
450typedef struct EL_DQTR {
451 uint8_t tb : 5; /* Timer bits; should be multiple of 4. */
452 uint8_t res : 3; /* Reserved. */
453} GA_DQTR;
454AssertCompile(sizeof(GA_DQTR) == sizeof(uint8_t));
455
456/** Gate Array Configuration Register. */
457typedef struct EL_GACFR {
458 uint8_t mbs : 3; /* Memory Bank Select. */
459 uint8_t rsel : 1; /* RAM Select. */
460 uint8_t test : 1; /* Makes GA counters run at 10 MHz. */
461 uint8_t ows : 1; /* 0 Wait State for Gate Array. */
462 uint8_t tcm : 1; /* Terminal Count Mask for DMA (block interrupt if set). */
463 uint8_t nim : 1; /* NIC Interrupt Mask (block interrupt if set). */
464} GA_GACFR;
465AssertCompile(sizeof(GA_GACFR) == sizeof(uint8_t));
466
467/** Gate Array Configuration Register. */
468typedef struct EL_GACR {
469 uint8_t rst : 1; /* Hard reset GA/NIC. */
470 uint8_t xsel : 1; /* Transceiver Select. */
471 uint8_t ealo : 1; /* Window low 16 bytes of PROM to I/O space. */
472 uint8_t eahi : 1; /* Window high 16 bytes of PROM to I/O space. */
473 uint8_t share : 1; /* Enable interrupt sharing. */
474 uint8_t dbsel : 1; /* Double Buffer Select for FIFOs. */
475 uint8_t ddir : 1; /* DMA Direction (1=host to adapter). */
476 uint8_t start : 1; /* Start Gate Array DMA. */
477} GA_GACR;
478AssertCompile(sizeof(GA_GACR) == sizeof(uint8_t));
479
480/** Gate Array Status Register. */
481typedef struct EL_STREG {
482 uint8_t rev : 3; /* Gate Array Revision. */
483 uint8_t dip : 1; /* DMA In Progress. */
484 uint8_t dtc : 1; /* DMA Terminal Count. */
485 uint8_t oflw : 1; /* Data Overflow. */
486 uint8_t uflw : 1; /* Data Underflow. */
487 uint8_t dprdy : 1; /* Data Port Ready. */
488} GA_STREG;
489AssertCompile(sizeof(GA_STREG) == sizeof(uint8_t));
490
491/** Gate Array Interrupt/DMA Configuration. */
492typedef struct EL_IDCFR {
493 uint8_t drq1 : 1; /* Enable DRQ 1. */
494 uint8_t drq2 : 1; /* Enable DRQ 2. */
495 uint8_t drq3 : 1; /* Enable DRQ 3. */
496 uint8_t res : 1; /* Unused. */
497 uint8_t irq2 : 1; /* Enable IRQ 2. */
498 uint8_t irq3 : 1; /* Enable IRQ 3. */
499 uint8_t irq4 : 1; /* Enable IRQ 4. */
500 uint8_t irq5 : 1; /* Enable IRQ 5. */
501} GA_IDCFR;
502AssertCompile(sizeof(GA_IDCFR) == sizeof(uint8_t));
503
504/** Current DMA Address. */
505typedef struct EL_CDADR {
506 uint8_t cdadr_lsb; /* Current DMA Address LSB. */
507 uint8_t cdadr_msb; /* Current DMA Address MSB. */
508} GA_CDADR;
509AssertCompile(sizeof(GA_CDADR) == sizeof(uint16_t));
510
511/** 3C503 Gate Array state. */
512typedef struct EL_GA_s {
513 uint8_t PSTR; /* Page Start Register. */
514 uint8_t PSPR; /* Page Stop Register. */
515 union {
516 uint8_t DQTR; /* DRQ Timer Register. */
517 GA_DQTR dqtr;
518 };
519 uint8_t BCFR; /* Base Configuration Register (R/O). */
520 uint8_t PCFR; /* Boot PROM Configuration Register (R/O). */
521 union {
522 uint8_t GACFR;
523 GA_GACFR gacfr; /* Gate Array Configuration Register. */
524 };
525 union {
526 uint8_t GACR; /* Gate Array Control Register. */
527 GA_GACR gacr;
528 };
529 union {
530 uint8_t STREG; /* Gate Array Status Register (R/O). */
531 GA_STREG streg;
532 };
533 union {
534 uint8_t IDCFR; /* Interrupt/DMA Configuration Register. */
535 GA_IDCFR idcfr;
536 };
537 uint8_t DAMSB; /* DMA Address MSB. */
538 uint8_t DALSB; /* DMA Address LSB. */
539 uint8_t VPTR2; /* Vector Pointer 2. */
540 uint8_t VPTR1; /* Vector Pointer 1. */
541 uint8_t VPTR0; /* Vector Pointer 0. */
542 union {
543 uint16_t CDADR; /* Current DMA address (internal state). */
544 GA_CDADR cdadr;
545 };
546 bool fGaIrq; /* Gate Array IRQ (internal state). */
547} EL_GA, *PEL_GA;
548
549/** DP8390 core register offsets. */
550#define DPR_CR 0
551
552#define DPR_P0_R_CLDA0 1
553#define DPR_P0_W_PSTART 1
554#define DPR_P0_R_CLDA1 2
555#define DPR_P0_W_PSTOP 2
556#define DPR_P0_BNRY 3
557#define DPR_P0_R_TSR 4
558#define DPR_P0_W_TPSR 4
559#define DPR_P0_R_NCR 5
560#define DPR_P0_W_TBCR0 5
561#define DPR_P0_R_FIFO 6
562#define DPR_P0_W_TBCR1 6
563#define DPR_P0_ISR 7
564#define DPR_P0_R_CRDA0 8
565#define DPR_P0_W_RSAR0 8
566#define DPR_P0_R_CRDA1 9
567#define DPR_P0_W_RSAR1 9
568#define DPR_P0_W_RBCR0 10
569#define DPR_P0_W_RBCR1 11
570#define DPR_P0_R_RSR 12
571#define DPR_P0_W_RCR 12
572#define DPR_P0_R_CNTR0 13
573#define DPR_P0_W_TCR 13
574#define DPR_P0_R_CNTR1 14
575#define DPR_P0_W_DCR 14
576#define DPR_P0_R_CNTR2 15
577#define DPR_P0_W_IMR 15
578
579#define DPR_P1_CURR 7
580
581#define DPR_P2_R_PSTART 1
582#define DPR_P2_W_CLDA0 1
583#define DPR_P2_R_PSTOP 2
584#define DPR_P2_W_CLDA1 2
585#define DPR_P2_RNXTPP 3 /* Remote Next Packet Pointer. */
586#define DPR_P2_R_TPSR 4
587#define DPR_P2_LNXTPP 5 /* Local Next Packet Pointer. */
588#define DPR_P2_ADRCU 6 /* Address Counter (Upper). */
589#define DPR_P2_ADRCL 7 /* Address Counter (Lower). */
590#define DPR_P2_R_RCR 12
591#define DPR_P2_R_TCR 13
592#define DPR_P2_R_DCR 14
593#define DPR_P2_R_IMR 15
594
595
596/** DP8390 Packet Header. */
597typedef struct DP_PKT_HDR {
598 uint8_t rcv_stat; /* Receive Status. */
599 uint8_t next_ptr; /* Next Packet Pointer. */
600 uint16_t byte_cnt; /* Receive byte count. */
601} DP_PKT_HDR;
602
603/** Select values for CR.RD field. */
604#define DP_CR_RDMA_INVL 0 /* Invalid value. */
605#define DP_CR_RDMA_RD 1 /* Remote Read. */
606#define DP_CR_RDMA_WR 2 /* Remote Write. */
607#define DP_CR_RDMA_SP 3 /* Send Packet. */
608#define DP_CR_RDMA_ABRT 4 /* Abort Remote DMA. */
609
610/** DP8390 Command Register (CR). */
611typedef struct DP_CR {
612 uint8_t STP : 1; /* Stop. */
613 uint8_t STA : 1; /* Start. */
614 uint8_t TXP : 1; /* Transmit Packet. */
615 uint8_t RD : 3; /* Remote DMA Command. */
616 uint8_t PS : 2; /* Page Select. */
617} DP_CR;
618AssertCompile(sizeof(DP_CR) == sizeof(uint8_t));
619
620/** DP8390 Interrupt Status Register (ISR). */
621typedef struct DP_ISR {
622 uint8_t PRX : 1; /* Packet Received. */
623 uint8_t PTX : 1; /* Packet Transmitted. */
624 uint8_t RXE : 1; /* Receive Error. */
625 uint8_t TXE : 1; /* Transmit Error. */
626 uint8_t OVW : 1; /* Overwrite Warning (no receive buffers). */
627 uint8_t CNT : 1; /* Counter Overflow. */
628 uint8_t RDC : 1; /* Remote DMA Complete. */
629 uint8_t RST : 1; /* Reset Status. */
630} DP_ISR;
631AssertCompile(sizeof(DP_ISR) == sizeof(uint8_t));
632
633/** DP8390 Interrupt Mask Register (IMR). */
634typedef struct DP_IMR {
635 uint8_t PRXE : 1; /* Packet Received Interrupt Enable. */
636 uint8_t PTXE : 1; /* Packet Transmitted Interrupt Enable. */
637 uint8_t RXEE : 1; /* Receive Error Interrupt Enable. */
638 uint8_t TXEE : 1; /* Transmit Error Interrupt Enable. */
639 uint8_t OVWE : 1; /* Overwrite Warning Interrupt Enable. */
640 uint8_t CNTE : 1; /* Counter Overflow Interrupt Enable. */
641 uint8_t RDCE : 1; /* DMA Complete Interrupt Enable. */
642 uint8_t res : 1; /* Reserved. */
643} DP_IMR;
644AssertCompile(sizeof(DP_IMR) == sizeof(uint8_t));
645
646/** DP8390 Data Configuration Register (DCR). */
647typedef struct DP_DCR {
648 uint8_t WTS : 1; /* Word Transfer Select. */
649 uint8_t BOS : 1; /* Byte Order Select. */
650 uint8_t LAS : 1; /* Long Address Select. */
651 uint8_t LS : 1; /* Loopback Select. */
652 uint8_t ARM : 1; /* Auto-Initialize Remote. */
653 uint8_t FT : 2; /* Fifo Threshold Select. */
654 uint8_t res : 1; /* Reserved. */
655} DP_DCR;
656AssertCompile(sizeof(DP_DCR) == sizeof(uint8_t));
657
658/** Transmit Configuration Register (TCR). */
659typedef struct DP_TCR {
660 uint8_t CRC : 1; /* Inhibit CRC. */
661 uint8_t LB : 2; /* Loopback Control. */
662 uint8_t ATD : 1; /* Auto Transmit Disable. */
663 uint8_t OFST : 1; /* Collision Offset Enable. */
664 uint8_t res : 3; /* Reserved. */
665} DP_TCR;
666AssertCompile(sizeof(DP_TCR) == sizeof(uint8_t));
667
668/** Transmit Status Register (TSR). */
669typedef struct DP_TSR {
670 uint8_t PTX : 1; /* Packet Transmitted. */
671 uint8_t DFR : 1; /* Non-Deferred Transmission (reserved in DP83901A). */
672 uint8_t COL : 1; /* Transmit Collided. */
673 uint8_t ABT : 1; /* Transmit Aborted. */
674 uint8_t CRS : 1; /* Carrier Sense Lost. */
675 uint8_t FU : 1; /* FIFO Underrun. */
676 uint8_t CDH : 1; /* CD Heartbeat. */
677 uint8_t OWC : 1; /* Out of Window Collision. */
678} DP_TSR;
679AssertCompile(sizeof(DP_TSR) == sizeof(uint8_t));
680
681/** Receive Configuration Register (RCR). */
682typedef struct DP_RCR {
683 uint8_t SEP : 1; /* Save Errored Packets. */
684 uint8_t AR : 1; /* Accept Runt Packets. */
685 uint8_t AB : 1; /* Accept Broadcast. */
686 uint8_t AM : 1; /* Accept Multicast. */
687 uint8_t PRO : 1; /* Promiscuous Physical. */
688 uint8_t MON : 1; /* Monitor Mode. */
689 uint8_t res : 2; /* Reserved. */
690} DP_RCR;
691AssertCompile(sizeof(DP_RCR) == sizeof(uint8_t));
692
693/** Receive Status Register (RSR). */
694typedef struct DP_RSR {
695 uint8_t PRX : 1; /* Packet Received Intact. */
696 uint8_t CRC : 1; /* CRC Error. */
697 uint8_t FAE : 1; /* Frame Alignment Error. */
698 uint8_t FO : 1; /* FIFO Overrun. */
699 uint8_t MPA : 1; /* Missed Packet. */
700 uint8_t PHY : 1; /* Physical/Multicast Address. */
701 uint8_t DIS : 1; /* Receiver Disabled. */
702 uint8_t DFR : 1; /* Deferring. */
703} DP_RSR;
704AssertCompile(sizeof(DP_RSR) == sizeof(uint8_t));
705
706/** Transmit Byte Count Register. */
707typedef struct DP_TBCR {
708 uint8_t TBCR0;
709 uint8_t TBCR1;
710} DP_TBCR;
711AssertCompile(sizeof(DP_TBCR) == sizeof(uint16_t));
712
713/** Current Local DMA Address. */
714typedef struct DP_CLDA {
715 uint8_t CLDA0;
716 uint8_t CLDA1;
717} DP_CLDA;
718AssertCompile(sizeof(DP_CLDA) == sizeof(uint16_t));
719
720/** Remote Start Address Register. */
721typedef struct DP_RSAR {
722 uint8_t RSAR0;
723 uint8_t RSAR1;
724} DP_RSAR;
725AssertCompile(sizeof(DP_RSAR) == sizeof(uint16_t));
726
727/** Remote Byte Count Register. */
728typedef struct DP_RBCR {
729 uint8_t RBCR0;
730 uint8_t RBCR1;
731} DP_RBCR;
732AssertCompile(sizeof(DP_RBCR) == sizeof(uint16_t));
733
734/** Current Remote DMA Address. */
735typedef struct DP_CRDA {
736 uint8_t CRDA0;
737 uint8_t CRDA1;
738} DP_CRDA;
739AssertCompile(sizeof(DP_CRDA) == sizeof(uint16_t));
740
741/** Page 1 registers. */
742/* All registers read/write without side effects, unlike pages 0/2. */
743typedef struct DP_PG1 {
744 uint8_t dummy_cr;
745 uint8_t PAR[6]; /* Physical Address PAR0-PAR5. */
746 uint8_t dummy_curr; /* Current Page Register. */
747 uint8_t MAR[8]; /* Multicast Address Register MAR0-MAR7. */
748} DP_PG1;
749AssertCompile(sizeof(DP_PG1) == 16);
750
751/** DP8390 FIFO. Not all of the state is explicitly accessible. */
752typedef struct DP_FIFO {
753 uint8_t rp; /* Read pointer. */
754 uint8_t wp; /* Write pointer. */
755 uint8_t fifo[16]; /* 16 bytes of FIFO. */
756} DP_FIFO;
757
758/**
759 * Core DP8390 chip state.
760 */
761typedef struct DP8390CORE
762{
763 union {
764 uint8_t CR; /* Command Register. */
765 DP_CR cr;
766 };
767 union {
768 uint8_t DCR; /* Data Control Register. */
769 DP_DCR dcr;
770 };
771 /* Interrupt control. */
772 union {
773 uint8_t ISR; /* Interrupt Status Register. */
774 DP_ISR isr;
775 };
776 union {
777 uint8_t IMR; /* Interrupt Mask Register. */
778 DP_IMR imr;
779 };
780 /* Receive state. */
781 union {
782 uint8_t RCR; /* Receive Control Register. */
783 DP_RCR rcr;
784 };
785 union {
786 uint8_t RSR; /* Receive Status register. */
787 DP_RSR rsr;
788 };
789 /* Transmit State. */
790 union {
791 uint8_t TCR; /* Transmit Control Register. */
792 DP_TCR tcr;
793 };
794 union {
795 uint8_t TSR; /* Transmit Status register. */
796 DP_TSR tsr;
797 };
798 uint8_t NCR; /* Number of Collisions Register. */
799 /* Local DMA transmit state. */
800 uint8_t TPSR; /* Transmit Page Start. */
801 union {
802 uint16_t TBCR; /* Transmit Byte Count. */
803 DP_TBCR tbcr;
804 };
805 /* Local DMA receive state. */
806 union {
807 uint16_t CLDA; /* Current Local DMA Address. */
808 DP_CLDA clda;
809 };
810 uint8_t PSTART; /* Page Start. */
811 uint8_t PSTOP; /* Page Stop. */
812 uint8_t CURR; /* Current Page. */
813 uint8_t BNRY; /* Boundary Page. Also spelled BNDRY. */
814 /* Remote DMA state. */
815 union {
816 uint16_t RSAR; /* Remote Start Address Register. */
817 DP_RSAR rsar;
818 };
819 union {
820 uint16_t RBCR; /* Remote Byte Count Register. */
821 DP_RBCR rbcr;
822 };
823 union {
824 uint16_t CRDA; /* Current Remote DMA Address. */
825 DP_CRDA crda;
826 };
827 /* Miscellaneous state. */
828 uint8_t lnxtpp; /* Local Next Packet Pointer. */
829 uint8_t rnxtpp; /* Remote Next Packet Pointer. */
830 /* Tally counters. */
831 uint8_t CNTR0; /* Frame Alignment Errors. */
832 uint8_t CNTR1; /* CRC Errors. */
833 uint8_t CNTR2; /* Missed Packet Errors. */
834 union {
835 uint8_t PG1[sizeof(DP_PG1)];
836 DP_PG1 pg1; /* All Page 1 Registers. */
837 };
838 DP_FIFO fifo; /* The internal FIFO. */
839} DP8390CORE, *PDP8390CORE;
840
841/**
842 * DP8390-based card state.
843 */
844typedef struct DPNICSTATE
845{
846 /** Restore timer.
847 * This is used to disconnect and reconnect the link after a restore. */
848 TMTIMERHANDLE hTimerRestore;
849
850 /** Transmit signaller. */
851 PDMTASKHANDLE hXmitTask;
852 /** Receive ready signaller. */
853 PDMTASKHANDLE hCanRxTask;
854
855 /** Emulated device type. */
856 uint8_t uDevType;
857 /** State of the card's interrupt request signal. */
858 bool fNicIrqActive;
859
860 /** Core DP8390 chip state. */
861 DP8390CORE core;
862
863 /** WD80x3 Control Register 1. */
864 union {
865 uint8_t CTRL1;
866 WD_CTRL1 ctrl1;
867 };
868 /** WD80x3 Control Register 2. */
869 union {
870 uint8_t CTRL2;
871 WD_CTRL2 ctrl2;
872 };
873
874 /** 3C503 Gate Array state. */
875 EL_GA ga;
876 /** The 3C503 soft-configured ISA DMA channel. */
877 uint8_t uElIsaDma;
878
879 /** The PROM contents. 32 bytes addressable, R/O. */
880 uint8_t aPROM[32];
881
882 /** Shared RAM base. */
883 RTGCPHYS MemBase;
884 /** Shared RAM MMIO region handle. */
885 PGMMMIO2HANDLE hSharedMem;
886 /** Shared RAM size. */
887 RTGCPHYS cbMemSize;
888
889 /** Base port of the I/O space region. */
890 RTIOPORT IOPortBase;
891 /** The configured ISA IRQ. */
892 uint8_t uIsaIrq;
893 /** The configured ISA DMA channel. */
894 uint8_t uIsaDma;
895 /** If set the link is currently up. */
896 bool fLinkUp;
897 /** If set the link is temporarily down because of a saved state load. */
898 bool fLinkTempDown;
899 /** Number of times we've reported the link down. */
900 uint16_t cLinkDownReported;
901 /** Number of times we've postponed the link restore. */
902 uint16_t cLinkRestorePostponed;
903
904 /** The "hardware" MAC address. */
905 RTMAC MacConfigured;
906
907 /** Set if DPNICSTATER3::pDrv is not NULL. */
908 bool fDriverAttached;
909 /** The LED. */
910 PDMLED Led;
911 /** Status LUN: The LED ports. */
912 PDMILEDPORTS ILeds;
913 /** Partner of ILeds. */
914 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
915
916 /** Access critical section. */
917 PDMCRITSECT CritSect;
918 /** Event semaphore for blocking on receive. */
919 RTSEMEVENT hEventOutOfRxSpace;
920 /** We are waiting/about to start waiting for more receive buffers. */
921 bool volatile fMaybeOutOfSpace;
922
923 /* MS to wait before we enable the link. */
924 uint32_t cMsLinkUpDelay;
925 /** The device instance number (for logging). */
926 uint32_t iInstance;
927
928 STAMCOUNTER StatReceiveBytes;
929 STAMCOUNTER StatTransmitBytes;
930#ifdef VBOX_WITH_STATISTICS
931 STAMPROFILEADV StatIOReadRZ;
932 STAMPROFILEADV StatIOReadR3;
933 STAMPROFILEADV StatIOWriteRZ;
934 STAMPROFILEADV StatIOWriteR3;
935 STAMPROFILEADV StatReceive;
936 STAMPROFILEADV StatTransmitR3;
937 STAMPROFILEADV StatTransmitRZ;
938 STAMPROFILE StatTransmitSendR3;
939 STAMPROFILE StatTransmitSendRZ;
940 STAMPROFILE StatRxOverflow;
941 STAMCOUNTER StatRxOverflowWakeup;
942 STAMCOUNTER StatRxCanReceiveNow;
943 STAMCOUNTER StatRxCannotReceiveNow;
944 STAMPROFILEADV StatInterrupt;
945 STAMCOUNTER StatDropPktMonitor;
946 STAMCOUNTER StatDropPktRcvrDis;
947 STAMCOUNTER StatDropPktVeryShort;
948 STAMCOUNTER StatDropPktVMNotRunning;
949 STAMCOUNTER StatDropPktNoLink;
950 STAMCOUNTER StatDropPktNoMatch;
951 STAMCOUNTER StatDropPktNoBuffer;
952#endif /* VBOX_WITH_STATISTICS */
953
954 /** NIC-specific ISA I/O ports. */
955 IOMIOPORTHANDLE hIoPortsNic;
956
957 /** Common DP8390 core I/O ports. */
958 IOMIOPORTHANDLE hIoPortsCore;
959
960 /** The runt pad buffer (only really needs 60 bytes). */
961 uint8_t abRuntBuf[64];
962
963 /** The packet buffer. */
964 uint8_t abLocalRAM[DPNIC_MEM_SIZE];
965
966 /** The loopback transmit buffer (avoid stack allocations). */
967 uint8_t abLoopBuf[DPNIC_MEM_SIZE]; /// @todo Can this be smaller?
968} DPNICSTATE, *PDPNICSTATE;
969
970
971/**
972 * DP8390 state for ring-3.
973 *
974 * @implements PDMIBASE
975 * @implements PDMINETWORKDOWN
976 * @implements PDMINETWORKCONFIG
977 * @implements PDMILEDPORTS
978 */
979typedef struct DPNICSTATER3
980{
981 /** Pointer to the device instance. */
982 PPDMDEVINSR3 pDevIns;
983 /** Pointer to the connector of the attached network driver. */
984 PPDMINETWORKUPR3 pDrv;
985 /** Pointer to the attached network driver. */
986 R3PTRTYPE(PPDMIBASE) pDrvBase;
987 /** LUN\#0 + status LUN: The base interface. */
988 PDMIBASE IBase;
989 /** LUN\#0: The network port interface. */
990 PDMINETWORKDOWN INetworkDown;
991 /** LUN\#0: The network config port interface. */
992 PDMINETWORKCONFIG INetworkConfig;
993
994 /** Status LUN: The LED ports. */
995 PDMILEDPORTS ILeds;
996 /** Partner of ILeds. */
997 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector;
998} DPNICSTATER3;
999/** Pointer to a DP8390 state structure for ring-3. */
1000typedef DPNICSTATER3 *PDPNICSTATER3;
1001
1002
1003/**
1004 * DP8390 state for ring-0.
1005 */
1006typedef struct DPNICSTATER0
1007{
1008 /** Pointer to the connector of the attached network driver. */
1009 PPDMINETWORKUPR0 pDrv;
1010} DPNICSTATER0;
1011/** Pointer to a DP8390 state structure for ring-0. */
1012typedef DPNICSTATER0 *PDPNICSTATER0;
1013
1014
1015/**
1016 * DP8390 state for raw-mode.
1017 */
1018typedef struct DPNICSTATERC
1019{
1020 /** Pointer to the connector of the attached network driver. */
1021 PPDMINETWORKUPRC pDrv;
1022} DPNICSTATERC;
1023/** Pointer to a DP8390 state structure for raw-mode. */
1024typedef DPNICSTATERC *PDPNICSTATERC;
1025
1026
1027/** The DP8390 state structure for the current context. */
1028typedef CTX_SUFF(DPNICSTATE) DPNICSTATECC;
1029/** Pointer to a DP8390 state structure for the current
1030 * context. */
1031typedef CTX_SUFF(PDPNICSTATE) PDPNICSTATECC;
1032
1033
1034#ifndef VBOX_DEVICE_STRUCT_TESTCASE
1035
1036
1037/*********************************************************************************************************************************
1038* Internal Functions *
1039*********************************************************************************************************************************/
1040
1041static int dp8390CoreAsyncXmitLocked(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PDPNICSTATECC pThisCC, bool fOnWorkerThread);
1042
1043/**
1044 * Checks if the link is up.
1045 * @returns true if the link is up.
1046 * @returns false if the link is down.
1047 */
1048DECLINLINE(bool) dp8390IsLinkUp(PDPNICSTATE pThis)
1049{
1050 return pThis->fDriverAttached && !pThis->fLinkTempDown && pThis->fLinkUp;
1051}
1052
1053
1054/* Table and macro borrowed from DevPCNet.cpp. */
1055#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
1056
1057/* generated using the AUTODIN II polynomial
1058 * x^32 + x^26 + x^23 + x^22 + x^16 +
1059 * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
1060 */
1061static const uint32_t crctab[256] =
1062{
1063 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
1064 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
1065 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
1066 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
1067 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
1068 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
1069 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
1070 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
1071 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
1072 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
1073 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
1074 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
1075 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
1076 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
1077 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
1078 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
1079 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
1080 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
1081 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
1082 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
1083 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
1084 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
1085 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
1086 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
1087 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
1088 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
1089 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
1090 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
1091 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
1092 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
1093 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
1094 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
1095 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
1096 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
1097 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1098 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
1099 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
1100 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
1101 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
1102 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1103 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
1104 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
1105 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
1106 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
1107 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1108 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
1109 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
1110 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
1111 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
1112 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1113 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
1114 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
1115 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
1116 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
1117 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1118 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
1119 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
1120 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
1121 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
1122 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1123 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
1124 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
1125 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
1126 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
1127};
1128
1129
1130#ifndef ETHER_IS_MULTICAST /* Net/Open BSD macro it seems */
1131#define ETHER_IS_MULTICAST(a) ((*(uint8_t *)(a)) & 1)
1132#endif
1133
1134
1135/**
1136 * Check if incoming frame matches the station address.
1137 */
1138DECLINLINE(int) padr_match(PDPNICSTATE pThis, const uint8_t *buf)
1139{
1140 RTNETETHERHDR *hdr = (RTNETETHERHDR *)buf;
1141 int result;
1142
1143 /* Checks own address only; always enabled if receiver on. */
1144 result = !memcmp(hdr->DstMac.au8, pThis->core.pg1.PAR, 6);
1145
1146 return result;
1147}
1148
1149
1150/**
1151 * Check if incoming frame is an accepted broadcast frame.
1152 */
1153DECLINLINE(int) padr_bcast(PDPNICSTATE pThis, const uint8_t *buf)
1154{
1155 static uint8_t aBCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1156 RTNETETHERHDR *hdr = (RTNETETHERHDR *)buf;
1157 int result = pThis->core.rcr.AB && !memcmp(hdr->DstMac.au8, aBCAST, 6);
1158 return result;
1159}
1160
1161
1162/**
1163 * Check if incoming frame is an accepted multicast frame.
1164 */
1165DECLINLINE(int) padr_mcast(PDPNICSTATE pThis, const uint8_t *buf, int *mcast_type)
1166{
1167 uint32_t crc = UINT32_MAX;
1168 RTNETETHERHDR *hdr = (RTNETETHERHDR *)buf;
1169 int result = 0;
1170
1171 /* If multicast addresses are enabled, and the destination
1172 * address is in fact multicast, the address must be run through
1173 * the CRC generator and matched against the multicast filter
1174 * array.
1175 */
1176 if (pThis->core.rcr.AM && ETHER_IS_MULTICAST(hdr->DstMac.au8))
1177 {
1178 unsigned i;
1179 const uint8_t *p = buf;
1180 unsigned crc_frag, crc_rev;
1181 unsigned ma_bit_mask, ma_byte_idx;
1182
1183 /* Indicate to caller that the address is a multicast one, regardless
1184 * of whether it's accepted or not.
1185 */
1186 *mcast_type = 1;
1187
1188 for (i = 0; i < sizeof(hdr->DstMac); ++i)
1189 CRC(crc, *p++);
1190
1191 /* The top 6 bits of the CRC calculated from the destination address
1192 * becomes an index into the 64-bit multicast address register. Sadly
1193 * our CRC algorithm is bit-reversed (Ethernet shifts bits out MSB first)
1194 * so instead of the top 6 bits of the CRC we have to take the bottom 6
1195 * and reverse the bits.
1196 */
1197 crc_frag = crc & 63;
1198
1199 for (i = 0, crc_rev = 0; i < 6; ++i)
1200 crc_rev |= ((crc_frag >> i) & 1) * (0x20 >> i);
1201
1202 ma_bit_mask = 1 << (crc_rev & 7);
1203 ma_byte_idx = crc_rev / 8;
1204 Log3Func(("crc=%08X, crc_frag=%u, crc_rev=%u, ma_byte_idx=%u, ma_bit_mask=%02X\n", crc, crc_frag, crc_rev, ma_byte_idx, ma_bit_mask));
1205 Log3Func(("MAR: %02X:%02X:%02X:%02X %02X:%02X:%02X:%02X\n", pThis->core.pg1.MAR[0], pThis->core.pg1.MAR[1], pThis->core.pg1.MAR[2], pThis->core.pg1.MAR[3], pThis->core.pg1.MAR[4], pThis->core.pg1.MAR[5], pThis->core.pg1.MAR[6], pThis->core.pg1.MAR[7]));
1206
1207 /* The multicast filtering logic is fairly extensively
1208 * verified by EtherLink II diagnostics (3C503.EXE).
1209 */
1210 if (pThis->core.pg1.MAR[ma_byte_idx] & ma_bit_mask)
1211 {
1212 Log3Func(("Passed multicast filter\n"));
1213 result = 1;
1214 }
1215 }
1216
1217 return result;
1218}
1219
1220
1221/**
1222 * Check if incoming frame is an accepted promiscuous frame.
1223 */
1224DECLINLINE(int) padr_promi(PDPNICSTATE pThis, const uint8_t *buf)
1225{
1226 RTNETETHERHDR *hdr = (RTNETETHERHDR *)buf;
1227 int result = pThis->core.rcr.PRO && !ETHER_IS_MULTICAST(hdr->DstMac.au8);
1228 return result;
1229}
1230
1231
1232/**
1233 * Update the device IRQ line based on internal state.
1234 */
1235static void dp8390CoreUpdateIrq(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
1236{
1237 bool fCoreIrqActive = false;
1238 bool fNicIrqActive = false;
1239
1240 STAM_PROFILE_ADV_START(&pThis->StatInterrupt, a);
1241
1242 /* Set the ISR.CNT bit based on the counter state (top counter bits ANDed together). */
1243 pThis->core.isr.CNT = (pThis->core.CNTR0 & pThis->core.CNTR1 & pThis->core.CNTR2) >> 7;
1244
1245 /* IRQ is active if a bit is set in ISR and the corresponding bit
1246 * is set in IMR. No additional internal state needed.
1247 */
1248 Assert(!pThis->core.imr.res);
1249 if (pThis->core.ISR & pThis->core.IMR)
1250 fCoreIrqActive = true;
1251
1252 /* The 3C503 has additional interrupt sources and control. For other device
1253 * types, the extras magically work out to be a no-op.
1254 */
1255 pThis->ga.fGaIrq = pThis->ga.streg.dtc && !pThis->ga.gacfr.tcm;
1256 fNicIrqActive = (fCoreIrqActive && !pThis->ga.gacfr.nim) || (pThis->ga.streg.dtc && !pThis->ga.gacfr.tcm);
1257
1258 Log2Func(("#%d set irq fNicIrqActive=%d (fCoreIrqActive=%d, fGaIrq=%d)\n", pThis->iInstance, fNicIrqActive, fCoreIrqActive, pThis->ga.fGaIrq));
1259
1260 /* The IRQ line typically does not change. */
1261 if (RT_UNLIKELY(fNicIrqActive != pThis->fNicIrqActive))
1262 {
1263 LogFunc(("#%d IRQ=%d, state=%d\n", pThis->iInstance, pThis->uIsaIrq, fNicIrqActive));
1264 /// @todo Handle IRQ 2/9 elsewhere
1265 PDMDevHlpISASetIrq(pDevIns, pThis->uIsaIrq == 2 ? 9 : pThis->uIsaIrq, fNicIrqActive);
1266 pThis->fNicIrqActive = fNicIrqActive;
1267 }
1268 STAM_PROFILE_ADV_STOP(&pThis->StatInterrupt, a);
1269}
1270
1271
1272/**
1273 * Perform a software reset of the NIC.
1274 */
1275static void dp8390CoreReset(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
1276{
1277 LogFlowFunc(("#%d:\n", pThis->iInstance));
1278
1279 /* DP8390 or DP83901A datasheet, section 11.0. */
1280 pThis->core.cr.TXP = 0;
1281 pThis->core.cr.STA = 0;
1282 pThis->core.cr.STP = 1;
1283 pThis->core.cr.RD = DP_CR_RDMA_ABRT;
1284 pThis->core.isr.RST = 1;
1285 pThis->core.IMR = 0;
1286 pThis->core.dcr.LAS = 0;
1287 pThis->core.tcr.LB = 0;
1288
1289 /// @todo Check if this really happens on soft reset
1290 /* Clear the internal FIFO including r/w pointers. */
1291 memset(&pThis->core.fifo, 0, sizeof(pThis->core.fifo));
1292
1293 /* Make sure the IRQ line us updated. */
1294 dp8390CoreUpdateIrq(pDevIns, pThis);
1295}
1296
1297#ifdef IN_RING3
1298
1299static DECLCALLBACK(void) dp8390R3WakeupReceive(PPDMDEVINS pDevIns)
1300{
1301 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
1302 LogFlowFunc(("#%d\n", pThis->iInstance));
1303 STAM_COUNTER_INC(&pThis->StatRxOverflowWakeup);
1304 if (pThis->hEventOutOfRxSpace != NIL_RTSEMEVENT)
1305 RTSemEventSignal(pThis->hEventOutOfRxSpace);
1306}
1307
1308/**
1309 * @callback_method_impl{FNPDMTASKDEV,
1310 * Signal to R3 that NIC is ready to receive a packet.
1311 */
1312static DECLCALLBACK(void) dpNicR3CanRxTaskCallback(PPDMDEVINS pDevIns, void *pvUser)
1313{
1314 RT_NOREF(pvUser);
1315 dp8390R3WakeupReceive(pDevIns);
1316}
1317
1318#endif /* IN_RING3 */
1319
1320/**
1321 * Read up to 256 bytes from a single page of local RAM.
1322 */
1323static void dpLocalRAMReadBuf(PDPNICSTATE pThis, uint16_t addr, unsigned cb, uint8_t *pDst)
1324{
1325 if ((RT_LOBYTE(addr) + cb) > 256)
1326 {
1327 LogFunc(("#%d: addr=%04X, cb=%X, cb!!\n", pThis->iInstance, addr, cb));
1328 cb = 256 - RT_LOBYTE(addr);
1329 }
1330
1331 /* A single page is always either entirely inside or outside local RAM. */
1332 if (pThis->uDevType == DEV_NE1000)
1333 {
1334 /* Only 14 bits of address are decoded. */
1335 addr &= 0x3fff;
1336 if (addr >= 0x2000)
1337 {
1338 /* Local RAM is mapped at 2000h-3FFFh. */
1339 addr -= 0x2000;
1340 memcpy(pDst, &pThis->abLocalRAM[addr], cb);
1341 }
1342 else
1343 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1344 }
1345 else if (pThis->uDevType == DEV_NE2000)
1346 {
1347 /* Only 15 bits of address are decoded. */
1348 addr &= 0x7fff;
1349 if (addr >= 0x4000)
1350 {
1351 /* Local RAM is mapped at 4000h-7FFFh. */
1352 addr -= 0x4000;
1353 memcpy(pDst, &pThis->abLocalRAM[addr], cb);
1354 }
1355 else
1356 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1357 }
1358 else if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
1359 {
1360 /* Local RAM is mapped starting at address zero. */
1361 addr &= DPNIC_MEM_MASK;
1362 if (addr + cb <= DPNIC_MEM_SIZE)
1363 memcpy(pDst, &pThis->abLocalRAM[addr], cb);
1364 else
1365 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1366 }
1367 else if (pThis->uDevType == DEV_3C503)
1368 {
1369 /* Only 14 bits of address are decoded. */
1370 /// @todo Is there any internal wrap-around in the 3C503 too?
1371 addr &= 0x3fff;
1372 if (addr >= 0x2000)
1373 {
1374 /* Local RAM is mapped at 2000h-3FFFh. */
1375 addr -= 0x2000;
1376 memcpy(pDst, &pThis->abLocalRAM[addr], cb);
1377 }
1378 else
1379 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1380 }
1381 else
1382 {
1383 Assert(0);
1384 }
1385}
1386
1387
1388#ifdef IN_RING3
1389
1390/**
1391 * Write up to 256 bytes into a single page of local RAM.
1392 */
1393static void dpLocalRAMWriteBuf(PDPNICSTATE pThis, uint16_t addr, unsigned cb, const uint8_t *pSrc)
1394{
1395 if ((RT_LOBYTE(addr) + cb) > 256)
1396 {
1397 LogFunc(("#%d: addr=%04X, cb=%X, cb!!\n", pThis->iInstance, addr, cb));
1398 cb = 256 - RT_LOBYTE(addr);
1399 }
1400
1401 /* A single page is always either entirely inside or outside local RAM. */
1402 if (pThis->uDevType == DEV_NE1000)
1403 {
1404 /* Only 14 bits of address are decoded. */
1405 addr &= 0x3fff;
1406 if (addr >= 0x2000)
1407 {
1408 /* Local RAM is mapped at 2000h-3FFFh. */
1409 addr -= 0x2000;
1410 memcpy(&pThis->abLocalRAM[addr], pSrc, cb);
1411 }
1412 else
1413 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1414 }
1415 else if (pThis->uDevType == DEV_NE2000)
1416 {
1417 /* Only 14 bits of address are decoded. */
1418 addr &= 0x7fff;
1419 if (addr >= 0x4000)
1420 {
1421 /* Local RAM is mapped at 4000h-7FFFh. */
1422 addr -= 0x4000;
1423 memcpy(&pThis->abLocalRAM[addr], pSrc, cb);
1424 }
1425 else
1426 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1427 }
1428 else if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
1429 {
1430 /* Local RAM is mapped starting at address zero. */
1431 addr &= DPNIC_MEM_MASK;
1432 if (addr + cb <= DPNIC_MEM_SIZE)
1433 memcpy(&pThis->abLocalRAM[addr], pSrc, cb);
1434 else
1435 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1436 }
1437 else if (pThis->uDevType == DEV_3C503)
1438 {
1439 /* Only 14 bits of address are decoded. */
1440 /// @todo Is there any internal wrap-around in the 3C503 too?
1441 addr &= 0x3fff;
1442 if (addr >= 0x2000)
1443 {
1444 /* Local RAM is mapped at 2000h-3FFFh. */
1445 addr -= 0x2000;
1446 memcpy(&pThis->abLocalRAM[addr], pSrc, cb);
1447 }
1448 else
1449 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
1450 }
1451 else
1452 {
1453 Assert(0);
1454 }
1455}
1456
1457
1458/**
1459 * Receive an arbitrarily long buffer into the receive ring starting at CLDA.
1460 * Update RSR, CLDA, and other state in the process.
1461 */
1462static void dp8390CoreReceiveBuf(PDPNICSTATE pThis, DP_RSR *pRsr, const uint8_t *src, unsigned cbLeft, bool fLast)
1463{
1464 LogFlow(("#%d: Initial CURR=%02X00 CLDA=%04X\n", pThis->iInstance, pThis->core.CURR, pThis->core.CLDA));
1465
1466 while (cbLeft)
1467 {
1468 unsigned cbWrite;
1469 unsigned cbPage;
1470
1471 /* Write at most up to the end of a page. */
1472 cbPage = cbWrite = 256 - pThis->core.clda.CLDA0;
1473 if (cbWrite > cbLeft)
1474 cbWrite = cbLeft;
1475 Log2Func(("#%d: cbLeft=%d CURR=%02X00 CLDA=%04X\n", pThis->iInstance, cbLeft, pThis->core.CURR, pThis->core.CLDA));
1476 dpLocalRAMWriteBuf(pThis, pThis->core.CLDA, cbWrite, src);
1477 src += cbWrite;
1478
1479 /* If this is the last fragment of a received frame, we need to
1480 * round CLDA up to the next page boundary to correctly evaluate
1481 * buffer overflows and the next pointer. Otherwise we just
1482 * add however much data we had so that we can continue writing
1483 * at the CLDA position.
1484 */
1485 if (fLast && (cbWrite == cbLeft))
1486 {
1487 Log3Func(("#%d: Round up: CLDA=%04X cbPage=%X\n", pThis->iInstance, pThis->core.CLDA, cbPage));
1488 pThis->core.CLDA += cbPage;
1489 }
1490 else
1491 pThis->core.CLDA += cbWrite;
1492
1493 Log3Func(("#%d: Final CURR=%02X00 CLDA=%04X\n", pThis->iInstance, pThis->core.CURR, pThis->core.CLDA));
1494 /* If at end of ring, wrap around. */
1495 if (pThis->core.clda.CLDA1 == pThis->core.PSTOP)
1496 pThis->core.clda.CLDA1 = pThis->core.PSTART;
1497
1498 /* Check for buffer overflow. */
1499 if (pThis->core.clda.CLDA1 == pThis->core.BNRY)
1500 {
1501 pThis->core.isr.OVW = 1;
1502 pThis->core.isr.RST = 1;
1503 pRsr->MPA = 1; /* Indicates to caller that receive was aborted. */
1504 STAM_COUNTER_INC(&pThis->StatDropPktNoBuffer);
1505 Log3Func(("#%d: PSTART=%02X00 PSTOP=%02X00 BNRY=%02X00 CURR=%02X00 -- overflow!\n", pThis->iInstance, pThis->core.PSTART, pThis->core.PSTOP, pThis->core.BNRY, pThis->core.CURR));
1506 break;
1507 }
1508 cbLeft -= cbWrite;
1509 }
1510}
1511
1512/**
1513 * Write incoming data into the packet buffer.
1514 */
1515static void dp8390CoreReceiveLocked(PPDMDEVINS pDevIns, PDPNICSTATE pThis, const uint8_t *src, size_t cbToRecv)
1516{
1517 int is_padr = 0, is_bcast = 0, is_mcast = 0, is_prom = 0;
1518 int mc_type = 0;
1519
1520 /*
1521 * Drop all packets if the VM is not running yet/anymore.
1522 */
1523 VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
1524 if ( enmVMState != VMSTATE_RUNNING
1525 && enmVMState != VMSTATE_RUNNING_LS)
1526 {
1527 STAM_COUNTER_INC(&pThis->StatDropPktVMNotRunning);
1528 return;
1529 }
1530
1531 /*
1532 * Drop all packets if the cable is not connected.
1533 */
1534 if (RT_UNLIKELY(!dp8390IsLinkUp(pThis)))
1535 {
1536 STAM_COUNTER_INC(&pThis->StatDropPktNoLink);
1537 return;
1538 }
1539
1540 /*
1541 * Drop everything if NIC is not started or in reset.
1542 */
1543 if (RT_UNLIKELY(!pThis->core.cr.STA || pThis->core.cr.STP))
1544 {
1545 STAM_COUNTER_INC(&pThis->StatDropPktRcvrDis);
1546 return;
1547 }
1548
1549 /* Drop impossibly short packets. The DP8390 requires a packet to have
1550 * at least 8 bytes to even qualify as a runt. We can also assume that
1551 * there is a complete destination address at that point.
1552 */
1553 if (RT_UNLIKELY(cbToRecv < 8))
1554 {
1555 STAM_COUNTER_INC(&pThis->StatDropPktVeryShort);
1556 return;
1557 }
1558
1559 LogFlowFunc(("#%d: size on wire=%d\n", pThis->iInstance, cbToRecv));
1560
1561 /*
1562 * Perform address matching. Packets which do not pass any address
1563 * matching logic are ignored.
1564 */
1565 if ( (is_padr = padr_match(pThis, src))
1566 || (is_bcast = padr_bcast(pThis, src))
1567 || (is_mcast = padr_mcast(pThis, src, &mc_type))
1568 || (is_prom = padr_promi(pThis, src)))
1569 {
1570 union {
1571 uint8_t nRSR;
1572 DP_RSR nRsr;
1573 };
1574 uint32_t fcs = 0;
1575
1576 nRSR = 0;
1577 Log2Func(("#%d Packet passed address filter (is_padr=%d, is_bcast=%d, is_mcast=%d, is_prom=%d), size=%d\n", pThis->iInstance, is_padr, is_bcast, is_mcast, is_prom, cbToRecv));
1578
1579 if (is_bcast || mc_type)
1580 nRsr.PHY = 1;
1581
1582 /* In Monitor Mode, just increment the tally counter. */
1583 if (RT_UNLIKELY(pThis->core.rcr.MON))
1584 {
1585 STAM_COUNTER_INC(&pThis->StatDropPktMonitor);
1586 nRsr.MPA = 1;
1587 if (pThis->core.CNTR2 <= 192)
1588 pThis->core.CNTR2++; /* Relies on UpdateIrq to be run. */
1589 }
1590 else
1591 {
1592 /* Error detection: FCS and frame alignment errors cannot happen,
1593 * likewise FIFO overruns can't.
1594 * Runts are padded up to the required minimum. Note that the DP8390
1595 * documentation considers packets smaller than 64 bytes to be runts,
1596 * but that includes 32 bits of FCS.
1597 */
1598
1599 /* See if we need to pad, and how much. Note that if there's any
1600 * room left in the receive buffers, a runt will fit even after padding.
1601 */
1602 if (RT_UNLIKELY(cbToRecv < 60))
1603 {
1604 /// @todo This really is kind of stupid. We shouldn't be doing any
1605 /// padding here, it should be done by the sending side!
1606 memset(pThis->abRuntBuf, 0, sizeof(pThis->abRuntBuf));
1607 memcpy(pThis->abRuntBuf, src, cbToRecv);
1608 cbToRecv = 60;
1609 src = pThis->abRuntBuf;
1610 }
1611
1612 LogFlowFunc(("#%d: PSTART=%02X00 PSTOP=%02X00 BNRY=%02X00 CURR=%02X00\n", pThis->iInstance, pThis->core.PSTART, pThis->core.PSTOP, pThis->core.BNRY, pThis->core.CURR));
1613
1614 /* All packets that passed the address filter are copied to local RAM.
1615 * Since the DP8390 does not know how long the frame is until it detects
1616 * end of frame, it can only detect an out-of-buffer condition after
1617 * filling up all available space. It then reports an error and rewinds
1618 * back to where it was before.
1619 *
1620 * We do not limit the incoming frame size except by available buffer space. /// @todo Except we do??
1621 */
1622
1623 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cbToRecv);
1624
1625 /* Copy incoming data to the packet buffer. Start by setting CLDA
1626 * to CURR + 4, leaving room for header.
1627 */
1628 pThis->core.CLDA = RT_MAKE_U16(4, pThis->core.CURR);
1629
1630 /* Receive the incoming frame. */
1631 Assert(cbToRecv < MAX_FRAME); /// @todo Can we actually do bigger?
1632 dp8390CoreReceiveBuf(pThis, &nRsr, src, (unsigned)cbToRecv, false);
1633 /// @todo Use the same method for runt padding?
1634
1635 /* If there was no overflow, add the FCS. */
1636 if (!nRsr.MPA)
1637 {
1638 fcs = 0xBADF00D; // Just fake it, does anyone care?
1639 dp8390CoreReceiveBuf(pThis, &nRsr, (uint8_t *)&fcs, sizeof(fcs), true);
1640 }
1641
1642 /* Error-free packets are considered intact. */
1643 if (!nRsr.CRC && !nRsr.FAE && !nRsr.FO && !nRsr.MPA)
1644 {
1645 nRsr.PRX = 1;
1646 pThis->core.isr.PRX = 1;
1647 }
1648 else
1649 pThis->core.isr.RXE = 1;
1650
1651 /* For 'intact' packets, write the packet header. */
1652 if (nRsr.PRX)
1653 {
1654 DP_PKT_HDR header;
1655
1656 /* Round up CLDA to the next page. */
1657 if (pThis->core.clda.CLDA0)
1658 pThis->core.CLDA = RT_MAKE_U16(0, pThis->core.clda.CLDA1 + 1);
1659
1660 /* If entire frame was successfully received, write the packet header at the old CURR. */
1661 header.rcv_stat = nRSR;
1662 header.next_ptr = pThis->core.clda.CLDA1;
1663 /// @todo big endian (WTS)
1664 header.byte_cnt = (uint16_t)cbToRecv + sizeof(fcs);
1665
1666 pThis->core.CLDA = RT_MAKE_U16(0, pThis->core.CURR);
1667 dpLocalRAMWriteBuf(pThis, pThis->core.CLDA, sizeof(header), (uint8_t *)&header);
1668 pThis->core.CLDA += sizeof(header);
1669
1670 pThis->core.CURR = header.next_ptr;
1671 }
1672 }
1673
1674 pThis->core.RSR = nRSR;
1675
1676 Log2Func(("Receive completed, size=%d, CURR=%02X00, RSR=%02X, ISR=%02X\n", cbToRecv, pThis->core.CURR, pThis->core.RSR, pThis->core.ISR));
1677 dp8390CoreUpdateIrq(pDevIns, pThis);
1678 }
1679 else
1680 {
1681 Log3Func(("#%d Packet did not pass address filter, size=%d\n", pThis->iInstance, cbToRecv));
1682 STAM_COUNTER_INC(&pThis->StatDropPktNoMatch);
1683 }
1684}
1685
1686#endif /* IN_RING3 */
1687
1688
1689/**
1690 * Transmit a packet from local memory.
1691 *
1692 * @returns VBox status code. VERR_TRY_AGAIN is returned if we're busy.
1693 *
1694 * @param pDevIns The device instance data.
1695 * @param pThis The device state data.
1696 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
1697 */
1698static int dp8390CoreXmitPacket(PPDMDEVINS pDevIns, PDPNICSTATE pThis, bool fOnWorkerThread)
1699{
1700 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
1701 RT_NOREF_PV(fOnWorkerThread);
1702 int rc;
1703
1704 /*
1705 * Grab the xmit lock of the driver as well as the DP8390 device state.
1706 */
1707 PPDMINETWORKUP pDrv = pThisCC->pDrv;
1708 if (pDrv)
1709 {
1710 rc = pDrv->pfnBeginXmit(pDrv, false /*fOnWorkerThread*/);
1711 if (RT_FAILURE(rc))
1712 return rc;
1713 }
1714 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
1715 if (RT_SUCCESS(rc))
1716 {
1717 /*
1718 * Do the transmitting.
1719 */
1720 int rc2 = dp8390CoreAsyncXmitLocked(pDevIns, pThis, pThisCC, false /*fOnWorkerThread*/);
1721 AssertReleaseRC(rc2);
1722
1723 /*
1724 * Release the locks.
1725 */
1726 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
1727 }
1728 else
1729 AssertLogRelRC(rc);
1730 if (pDrv)
1731 pDrv->pfnEndXmit(pDrv);
1732
1733 return rc;
1734}
1735
1736
1737#ifdef IN_RING3
1738
1739/**
1740 * @callback_method_impl{FNPDMTASKDEV,
1741 * This is just a very simple way of delaying sending to R3.
1742 */
1743static DECLCALLBACK(void) dpNicR3XmitTaskCallback(PPDMDEVINS pDevIns, void *pvUser)
1744{
1745 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
1746 NOREF(pvUser);
1747
1748 /*
1749 * Transmit if we can.
1750 */
1751 dp8390CoreXmitPacket(pDevIns, pThis, true /*fOnWorkerThread*/);
1752}
1753
1754#endif /* IN_RING3 */
1755
1756
1757/**
1758 * Allocates a scatter/gather buffer for a transfer.
1759 *
1760 * @returns See PPDMINETWORKUP::pfnAllocBuf.
1761 * @param pThis The device instance.
1762 * @param pThisCC The device state for current context.
1763 * @param cbMin The minimum buffer size.
1764 * @param fLoopback Set if we're in loopback mode.
1765 * @param pSgLoop Pointer to stack storage for the loopback SG.
1766 * @param ppSgBuf Where to return the SG buffer descriptor on success.
1767 * Always set.
1768 */
1769DECLINLINE(int) dp8390XmitAllocBuf(PDPNICSTATE pThis, PDPNICSTATECC pThisCC, size_t cbMin, bool fLoopback,
1770 PPDMSCATTERGATHER pSgLoop, PPPDMSCATTERGATHER ppSgBuf)
1771{
1772 int rc;
1773
1774 if (!fLoopback)
1775 {
1776 PPDMINETWORKUP pDrv = pThisCC->pDrv;
1777 if (RT_LIKELY(pDrv))
1778 {
1779 rc = pDrv->pfnAllocBuf(pDrv, cbMin, NULL /*pGso*/, ppSgBuf);
1780 AssertMsg(rc == VINF_SUCCESS || rc == VERR_TRY_AGAIN || rc == VERR_NET_DOWN || rc == VERR_NO_MEMORY, ("%Rrc\n", rc));
1781 if (RT_FAILURE(rc))
1782 *ppSgBuf = NULL;
1783 }
1784 else
1785 {
1786 rc = VERR_NET_DOWN;
1787 *ppSgBuf = NULL;
1788 }
1789 }
1790 else
1791 {
1792 /* Fake loopback allocator. */
1793 pSgLoop->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
1794 pSgLoop->cbUsed = 0;
1795 pSgLoop->cbAvailable = sizeof(pThis->abLoopBuf);
1796 pSgLoop->pvAllocator = pThis;
1797 pSgLoop->pvUser = NULL;
1798 pSgLoop->cSegs = 1;
1799 pSgLoop->aSegs[0].cbSeg = sizeof(pThis->abLoopBuf);
1800 pSgLoop->aSegs[0].pvSeg = pThis->abLoopBuf;
1801 *ppSgBuf = pSgLoop;
1802 rc = VINF_SUCCESS;
1803 }
1804 return rc;
1805}
1806
1807
1808/**
1809 * Sends the scatter/gather buffer.
1810 *
1811 * Wrapper around PDMINETWORKUP::pfnSendBuf, so check it out for the fine print.
1812 *
1813 * @returns See PDMINETWORKUP::pfnSendBuf.
1814 * @param pDevIns The device instance.
1815 * @param pThisCC The current context device state.
1816 * @param fLoopback Set if we're in loopback mode.
1817 * @param pSgBuf The SG to send.
1818 * @param fOnWorkerThread Set if we're being called on a work thread. Clear
1819 * if an EMT.
1820 */
1821DECLINLINE(int) dp8390CoreXmitSendBuf(PPDMDEVINS pDevIns, PDPNICSTATECC pThisCC, bool fLoopback, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
1822{
1823 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
1824 int rc;
1825 STAM_REL_COUNTER_ADD(&pThis->StatTransmitBytes, pSgBuf->cbUsed);
1826 if (!fLoopback)
1827 {
1828 STAM_PROFILE_START(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
1829 if (pSgBuf->cbUsed > 70) /* unqualified guess */
1830 pThis->Led.Asserted.s.fWriting = pThis->Led.Actual.s.fWriting = 1;
1831
1832 PPDMINETWORKUP pDrv = pThisCC->pDrv;
1833 if (RT_LIKELY(pDrv))
1834 {
1835 rc = pDrv->pfnSendBuf(pDrv, pSgBuf, fOnWorkerThread);
1836 AssertMsg(rc == VINF_SUCCESS || rc == VERR_NET_DOWN || rc == VERR_NET_NO_BUFFER_SPACE, ("%Rrc\n", rc));
1837 }
1838 else
1839 rc = VERR_NET_DOWN;
1840
1841 pThis->Led.Actual.s.fWriting = 0;
1842 STAM_PROFILE_STOP(&pThis->CTX_SUFF_Z(StatTransmitSend), a);
1843 }
1844 else
1845 {
1846 PDP8390CORE pCore = &pThis->core;
1847 union {
1848 uint8_t nRSR;
1849 DP_RSR nRsr;
1850 };
1851 unsigned ofs;
1852 uint32_t fcs = UINT32_MAX;
1853
1854 nRSR = 0;
1855
1856 /* Loopback on the DP8390 is so strange that it must be handled specially. */
1857 Assert(pSgBuf->pvAllocator == (void *)pThis);
1858 pThis->Led.Asserted.s.fReading = pThis->Led.Actual.s.fReading = 1;
1859
1860 LogFlowFunc(("#%d: loopback (DCR=%02X LB=%u TCR=%02X RCR=%02X, %u bytes)\n", pThis->iInstance, pCore->DCR, pCore->tcr.LB, pCore->TCR, pCore->RCR, pSgBuf->cbUsed));
1861 for (ofs = 0; ofs < pSgBuf->cbUsed; ofs += 16)
1862 Log((" %04X: %.*Rhxs\n", ofs, ofs + 16 < pSgBuf->cbUsed ? 16 : pSgBuf->cbUsed - ofs, &pThis->abLoopBuf[ofs]));
1863
1864 /* A packet shorter than 8 bytes is ignored by the receiving side. */
1865 if (pSgBuf->cbUsed < 8)
1866 return VINF_SUCCESS;
1867
1868 /* The loopback mode affects transmit status bits. */
1869 switch (pCore->tcr.LB)
1870 {
1871 case 1: /* Internal loopback within DP8390. */
1872 pCore->tsr.CDH = 1;
1873 pCore->tsr.CRS = 1;
1874 break;
1875 case 2: /* Loopback through serializer. */
1876 pCore->tsr.CDH = 1;
1877 break;
1878 case 3: /* External loopback. Requires a cable. */
1879 break;
1880 default:
1881 Assert(0);
1882 }
1883
1884 /* The CRC Inhibit controls whether transmit or receive path uses the
1885 * CRC circuitry. If transmit side uses CRC, receive always fails.
1886 * We always need to calculate the FCS because either the sending or
1887 * the receiving side uses it.
1888 */
1889 uint8_t *p;
1890 uint8_t *pktbuf = pThis->abLoopBuf; /// @todo Point into sgbuf instead?
1891 uint16_t pktlen = (uint16_t)pSgBuf->cbUsed;
1892 uint16_t fcslen = pktlen;
1893 uint8_t abFcs[4];
1894 bool fAddrMatched = true;
1895
1896 /* If the receiver side is calculating FCS, it needs to skip the last
1897 * bytes (which are the transmit-side FCS).
1898 */
1899 if (pCore->tcr.CRC && (pktlen > 4))
1900 fcslen -= 4;
1901
1902 p = pktbuf;
1903 while (p != &pktbuf[fcslen])
1904 CRC(fcs, *p++);
1905
1906 fcs = ~fcs;
1907 Log3Func(("FCS: %08X\n", fcs));
1908 for (ofs = 0; ofs < sizeof(abFcs); ++ofs)
1909 {
1910 abFcs[ofs] = (uint8_t)fcs;
1911 fcs >>= 8;
1912 }
1913
1914 /* The FIFO write pointer gets zeroed on each receive,
1915 * but the read pointer does not.
1916 */
1917 pCore->fifo.wp = 0;
1918
1919 if (pCore->tcr.CRC)
1920 {
1921 bool fGoodFcs = true;
1922 int is_padr = 0, is_bcast = 0, is_mcast = 0, is_prom = 0;
1923 int mc_type = 0;
1924
1925 /* Always put the first 8 bytes of the packet in the FIFO. */
1926 for (ofs = 0; ofs < 8; ++ofs)
1927 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = pktbuf[ofs];
1928
1929
1930 /* If the receiving side uses the CRC circuitry, it also performs
1931 * destination address matching.
1932 */
1933 if ( (is_padr = padr_match(pThis, pktbuf))
1934 || (is_bcast = padr_bcast(pThis, pktbuf))
1935 || (is_mcast = padr_mcast(pThis, pktbuf, &mc_type))
1936 || (is_prom = padr_promi(pThis, pktbuf)))
1937 {
1938 /* Receiving side checks the FCS. */
1939 fGoodFcs = !memcmp(&pktbuf[pktlen - 4], abFcs, sizeof(abFcs));
1940 Log2Func(("#%d: Address matched (is_padr=%d, is_bcast=%d, is_mcast=%d, is_prom=%d), checking FCS (fGoodFcs=%RTbool)\n", pThis->iInstance, is_padr, is_bcast, is_mcast, is_prom, fGoodFcs));
1941
1942 /* Now we have to update the FIFO. Since only 8 bytes are visible
1943 * in the FIFO after a receive, we can skip most of it.
1944 */
1945 for ( ; ofs < pktlen; ++ofs)
1946 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = pktbuf[ofs];
1947
1948 }
1949 else
1950 {
1951 nRsr.PRX = 1; /* Weird but true, for non-matching address only! */
1952 fAddrMatched = false;
1953 Log3Func(("#%d: Address NOT matched, ignoring FCS errors.\n", pThis->iInstance));
1954 }
1955
1956 /* The PHY bit is set when when an enabled broadcast packet is accepted,
1957 * but also when an enabled multicast packet arrives regardless of whether
1958 * it passes the MAR filter or not.
1959 */
1960 if (is_bcast || mc_type)
1961 nRsr.PHY = 1;
1962
1963 if (!fGoodFcs)
1964 nRsr.CRC = 1;
1965 }
1966 else
1967 {
1968 nRsr.CRC = 1; /* Always report CRC error if receiver isn't checking. */
1969
1970 /* Now we have to update the FIFO. Since only 8 bytes are visible
1971 * in the FIFO after a receive, we can skip most of it.
1972 */
1973 for (ofs = 0; ofs < pktlen; ++ofs)
1974 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = pktbuf[ofs];
1975
1976 /* Stuff the generated FCS in the FIFO. */
1977 for (ofs = 0; ofs < sizeof(abFcs); ++ofs)
1978 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = abFcs[ofs];
1979 }
1980
1981 /* And now put the packet length in the FIFO. */
1982 if (fAddrMatched || 1)
1983 {
1984 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = RT_LOBYTE(pktlen);
1985 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = RT_HIBYTE(pktlen);
1986 pCore->fifo.fifo[pCore->fifo.wp++ & 7] = RT_HIBYTE(pktlen); /* Yes, written twice! */
1987 }
1988
1989 Log(("FIFO: rp=%u, wp=%u\n", pCore->fifo.rp & 7, pCore->fifo.wp & 7));
1990 Log((" %Rhxs\n", &pCore->fifo.fifo));
1991
1992 if (nRsr.CRC)
1993 pCore->isr.RXE = 1;
1994 pCore->RSR = nRSR;
1995
1996 pThis->Led.Actual.s.fReading = 0;
1997
1998 /* Return success so that caller sets TSR.PTX and ISR.PTX. */
1999 rc = VINF_SUCCESS;
2000 }
2001 return rc;
2002}
2003
2004
2005/**
2006 * Reads the entire frame into the scatter gather buffer.
2007 */
2008DECLINLINE(void) dp8390CoreXmitRead(PPDMDEVINS pDevIns, const unsigned uLocalAddr, const unsigned cbFrame, PPDMSCATTERGATHER pSgBuf, bool fLoopback)
2009{
2010 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
2011 unsigned uOfs = 0;
2012 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
2013 Assert(pSgBuf->cbAvailable >= cbFrame);
2014
2015 pSgBuf->cbUsed = cbFrame;
2016
2017 LogFlowFunc(("#%d: uLocalAddr=%04X cbFrame=%d\n", pThis->iInstance, uLocalAddr, cbFrame));
2018 /* Have to figure out where the address is in local RAM. */
2019 if (pThis->uDevType == DEV_NE1000)
2020 {
2021 /* Only 14 bits of address are decoded. */
2022 uOfs = uLocalAddr & 0x3fff;
2023 if (uOfs >= 0x2000)
2024 {
2025 /* Local RAM is mapped at 2000h-3FFFh. */
2026 uOfs -= 0x2000;
2027 }
2028 else
2029 {
2030 /// @todo What are we supposed to do?!
2031 LogFunc(("#%d: uOfs=%u, don't know what to do!!\n", pThis->iInstance, uOfs));
2032 }
2033 }
2034 else if (pThis->uDevType == DEV_NE2000)
2035 {
2036 /* Only 15 bits of address are decoded. */
2037 uOfs = uLocalAddr & 0x7fff;
2038 if (uOfs >= 0x4000)
2039 {
2040 /* Local RAM is mapped at 4000h-7FFFh. */
2041 uOfs -= 0x4000;
2042 }
2043 else
2044 {
2045 /// @todo What are we supposed to do?!
2046 LogFunc(("#%d: uOfs=%u, don't know what to do!!\n", pThis->iInstance, uOfs));
2047 }
2048 }
2049 else if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
2050 {
2051 /* Not much to do, WD was nice enough to put the RAM at the start of DP8390's address space. */
2052 uOfs = uLocalAddr & DPNIC_MEM_MASK;
2053 }
2054 else if (pThis->uDevType == DEV_3C503)
2055 {
2056 /* Only 14 bits of address are decoded. */
2057 uOfs = uLocalAddr & 0x3fff;
2058 if (uOfs >= 0x2000)
2059 {
2060 /* Local RAM is mapped at 2000h-3FFFh. */
2061 uOfs -= 0x2000;
2062 }
2063 else
2064 {
2065 /// @todo What are we supposed to do?!
2066 LogFunc(("#%d: uOfs=%u, don't know what to do!!\n", pThis->iInstance, uOfs));
2067 }
2068 }
2069 else
2070 {
2071 Assert(0);
2072 }
2073
2074 if (!fLoopback)
2075 {
2076 /* Fast path for normal transmit, ignores DCR.WTS. */
2077 if (uOfs + cbFrame <= sizeof(pThis->abLocalRAM))
2078 memcpy(pSgBuf->aSegs[0].pvSeg, &pThis->abLocalRAM[uOfs], cbFrame);
2079 else
2080 memset(pSgBuf->aSegs[0].pvSeg, 0xEE, cbFrame);
2081 }
2082 else
2083 {
2084 /* If DCR.WTS is set, only every other byte actually goes through loopback. */
2085 const uint8_t *src = &pThis->abLocalRAM[uOfs];
2086 uint8_t *dst = (uint8_t *)pSgBuf->aSegs[0].pvSeg;
2087 int cbDst = cbFrame;
2088 int step = 1 << pThis->core.dcr.WTS;
2089
2090 /* Depending on DCR.BOS, take either odd or even bytes when DCR.WTS is set. */
2091 if (pThis->core.dcr.WTS && !pThis->core.dcr.BOS)
2092 ++src;
2093
2094 while (cbDst-- && (src <= &pThis->abLocalRAM[DPNIC_MEM_SIZE]))
2095 {
2096 *dst++ = *src;
2097 src += step;
2098 }
2099
2100 /* The address should perhaps wrap around -- depends on card design. */
2101 if (cbDst != -1)
2102 {
2103 while (cbDst--)
2104 *dst++ = 0xEE;
2105 }
2106 Assert(cbDst == -1);
2107 }
2108}
2109
2110/**
2111 * Try to transmit a frame.
2112 */
2113static void dp8390CoreStartTransmit(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
2114{
2115 /*
2116 * Transmit the packet if possible, defer it if we cannot do it
2117 * in the current context.
2118 */
2119 pThis->core.TSR = 0; /* Clear transmit status. */
2120 pThis->core.NCR = 0; /* Clear collision counter. */
2121#if defined(IN_RING0) || defined(IN_RC)
2122 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
2123 if (!pThisCC->pDrv)
2124 {
2125 int rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hXmitTask);
2126 AssertRC(rc);
2127 }
2128 else
2129#endif
2130 {
2131 int rc = dp8390CoreXmitPacket(pDevIns, pThis, false /*fOnWorkerThread*/);
2132 if (rc == VERR_TRY_AGAIN)
2133 rc = VINF_SUCCESS;
2134 AssertRC(rc);
2135 }
2136}
2137
2138
2139/**
2140 * If a packet is waiting, poke the receiving machinery.
2141 *
2142 * @threads EMT.
2143 */
2144static void dp8390CoreKickReceive(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
2145{
2146 if (pThis->fMaybeOutOfSpace)
2147 {
2148 LogFlow(("Poking receive thread.\n"));
2149#ifdef IN_RING3
2150 dp8390R3WakeupReceive(pDevIns);
2151#else
2152 int rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hCanRxTask);
2153 AssertRC(rc);
2154#endif
2155 }
2156}
2157
2158/**
2159 * Try transmitting a frame.
2160 *
2161 * @threads TX or EMT.
2162 */
2163static int dp8390CoreAsyncXmitLocked(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PDPNICSTATECC pThisCC, bool fOnWorkerThread)
2164{
2165 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
2166
2167 /*
2168 * Just drop it if not transmitting. Can happen with delayed transmits
2169 * if transmit was disabled in the meantime.
2170 */
2171 if (RT_UNLIKELY(!pThis->core.cr.TXP))
2172 {
2173 LogFunc(("#%d: Nope, CR.TXP is off (fOnWorkerThread=%RTbool)\n", pThis->iInstance, fOnWorkerThread));
2174 return VINF_SUCCESS;
2175 }
2176
2177 /*
2178 * Blast out data from the packet buffer.
2179 */
2180 int rc;
2181 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatTransmit), a);
2182 do
2183 {
2184 /* Don't send anything when the link is down. */
2185 if (RT_UNLIKELY( !dp8390IsLinkUp(pThis)
2186 && pThis->cLinkDownReported > DPNIC_MAX_LINKDOWN_REPORTED)
2187 )
2188 break;
2189
2190 bool const fLoopback = pThis->core.tcr.LB != 0;
2191 PDMSCATTERGATHER SgLoop;
2192 PPDMSCATTERGATHER pSgBuf;
2193
2194 /*
2195 * Sending is easy peasy, there is by definition always
2196 * a complete packet on hand.
2197 */
2198 unsigned cb = pThis->core.TBCR; /* Packet size. */
2199 const int adr = RT_MAKE_U16(0, pThis->core.TPSR);
2200 LogFunc(("#%d: cb=%d, adr=%04X\n", pThis->iInstance, cb, adr));
2201
2202 if (RT_LIKELY(dp8390IsLinkUp(pThis) || fLoopback))
2203 {
2204 if (RT_LIKELY(cb <= MAX_FRAME))
2205 {
2206 /* Loopback fun! */
2207 if (RT_UNLIKELY(fLoopback && pThis->core.dcr.WTS))
2208 {
2209 cb /= 2;
2210 Log(("Loopback with DCR.WTS set -> cb=%d\n", cb));
2211 }
2212
2213 rc = dp8390XmitAllocBuf(pThis, pThisCC, cb, fLoopback, &SgLoop, &pSgBuf);
2214 if (RT_SUCCESS(rc))
2215 {
2216 dp8390CoreXmitRead(pDevIns, adr, cb, pSgBuf, fLoopback);
2217 rc = dp8390CoreXmitSendBuf(pDevIns, pThisCC, fLoopback, pSgBuf, fOnWorkerThread);
2218 Log2Func(("#%d: rc=%Rrc\n", pThis->iInstance, rc));
2219 }
2220 else if (rc == VERR_TRY_AGAIN)
2221 {
2222 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
2223 LogFunc(("#%d: rc=%Rrc\n", pThis->iInstance, rc));
2224 return VINF_SUCCESS;
2225 }
2226 if (RT_SUCCESS(rc))
2227 {
2228 pThis->core.tsr.PTX = 1;
2229 pThis->core.isr.PTX = 1;
2230 }
2231 else
2232 {
2233 pThis->core.tsr.COL = 1; /* Pretend there was a collision. */
2234 pThis->core.isr.TXE = 1;
2235 }
2236 }
2237 else
2238 {
2239 /* Signal error, as this violates the Ethernet specs. Note that the DP8390
2240 * hardware does *not* limit the packet length.
2241 */
2242 LogRel(("DPNIC#%d: Attempt to transmit illegal giant frame (%u bytes) -> signaling error\n", pThis->iInstance, cb));
2243 pThis->core.tsr.OWC = 1; /* Pretend there was an out-of-window collision. */
2244 pThis->core.isr.TXE = 1;
2245 }
2246 }
2247 else
2248 {
2249 /* Signal a transmit error pretending there was a collision. */
2250 pThis->core.tsr.COL = 1;
2251 pThis->core.isr.TXE = 1;
2252 pThis->cLinkDownReported++;
2253 }
2254 /* Transmit officially done, update register state. */
2255 pThis->core.cr.TXP = 0;
2256 pThis->core.TBCR = 0;
2257 LogFlowFunc(("#%d: TSR=%02X, ISR=%02X\n", pThis->iInstance, pThis->core.TSR, pThis->core.ISR));
2258
2259 } while (0); /* No loop, because there isn't ever more than one packet to transmit. */
2260
2261 dp8390CoreUpdateIrq(pDevIns, pThis);
2262
2263 /* If there's anything waiting, this should be a good time to recheck. */
2264 dp8390CoreKickReceive(pDevIns, pThis);
2265
2266 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
2267
2268 return VINF_SUCCESS;
2269}
2270
2271/* -=-=-=-=-=- I/O Port access -=-=-=-=-=- */
2272
2273
2274static uint32_t dp8390CoreRead(PPDMDEVINS pDevIns, PDPNICSTATE pThis, int ofs)
2275{
2276 uint8_t val;
2277
2278 /* The 3C503 can read the PROM instead of the DP8390 registers. */
2279 if (pThis->ga.gacr.ealo)
2280 return pThis->aPROM[ofs % 0xf];
2281 else if (pThis->ga.gacr.eahi)
2282 return pThis->aPROM[16 + (ofs % 0xf)];
2283
2284 /* Command Register exists in all pages. */
2285 if (ofs == DPR_CR)
2286 return pThis->core.CR;
2287
2288 if (pThis->core.cr.PS == 0)
2289 {
2290 switch (ofs)
2291 {
2292 case DPR_P0_R_CLDA0:
2293 return pThis->core.clda.CLDA0;
2294 case DPR_P0_R_CLDA1:
2295 return pThis->core.clda.CLDA1;
2296 case DPR_P0_BNRY:
2297 return pThis->core.BNRY;
2298 case DPR_P0_R_TSR:
2299 return pThis->core.TSR;
2300 case DPR_P0_R_NCR:
2301 return pThis->core.NCR;
2302 case DPR_P0_R_FIFO:
2303 return pThis->core.fifo.fifo[pThis->core.fifo.rp++ & 7]; /// @todo Abstract the mask somehow?
2304 case DPR_P0_ISR:
2305 return pThis->core.ISR;
2306 case DPR_P0_R_CRDA0:
2307 return pThis->core.crda.CRDA0;
2308 case DPR_P0_R_CRDA1:
2309 return pThis->core.crda.CRDA1;
2310 case DPR_P0_R_RSR:
2311 return pThis->core.RSR;
2312 case DPR_P0_R_CNTR0:
2313 val = pThis->core.CNTR0;
2314 pThis->core.CNTR0 = 0; /* Cleared by reading. */
2315 dp8390CoreUpdateIrq(pDevIns, pThis);
2316 return val;
2317 case DPR_P0_R_CNTR1:
2318 val = pThis->core.CNTR1;
2319 pThis->core.CNTR1 = 0; /* Cleared by reading. */
2320 dp8390CoreUpdateIrq(pDevIns, pThis);
2321 return val;
2322 case DPR_P0_R_CNTR2:
2323 val = pThis->core.CNTR2;
2324 pThis->core.CNTR2 = 0; /* Cleared by reading. */
2325 dp8390CoreUpdateIrq(pDevIns, pThis);
2326 return val;
2327 default:
2328 return 0; /// @todo or 0xFF? or something else?
2329 }
2330 }
2331 else if (pThis->core.cr.PS == 1)
2332 {
2333 /* Page 1 is easy, most registers are stored directly. */
2334 if (ofs == DPR_P1_CURR)
2335 return pThis->core.CURR;
2336 else
2337 return pThis->core.PG1[ofs];
2338 }
2339 else if (pThis->core.cr.PS == 2)
2340 {
2341 /* Page 2 is for diagnostics. Reads many registers that
2342 * are write-only in Page 0.
2343 */
2344 switch (ofs)
2345 {
2346 case DPR_P2_R_PSTART:
2347 return pThis->core.PSTART;
2348 case DPR_P2_R_PSTOP:
2349 return pThis->core.PSTOP;
2350 case DPR_P2_RNXTPP:
2351 return pThis->core.rnxtpp;
2352 case DPR_P2_R_TPSR:
2353 return pThis->core.TPSR;
2354 case DPR_P2_LNXTPP:
2355 return pThis->core.lnxtpp;
2356 case DPR_P2_ADRCU:
2357 case DPR_P2_ADRCL:
2358 return 0; /// @todo What's this?
2359 case DPR_P2_R_RCR:
2360 return pThis->core.RCR;
2361 case DPR_P2_R_TCR:
2362 return pThis->core.TCR;
2363 case DPR_P2_R_DCR:
2364 return pThis->core.DCR;
2365 case DPR_P2_R_IMR:
2366 return pThis->core.IMR;
2367 default:
2368 return 0; /// @todo Or 0xFF? Or something else?
2369 }
2370 }
2371 else
2372 {
2373 /* Page 3 is undocumented and unimplemented. */
2374 LogFunc(("Reading page 3 register: ofs=%X!\n", ofs));
2375 return 0;
2376 }
2377}
2378
2379
2380static int dp8390CoreWriteCR(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t val)
2381{
2382 union {
2383 uint8_t nCR;
2384 DP_CR nCr;
2385 };
2386
2387 nCR = val;
2388 LogFlow(("val=%02X, old=%02X\n", val, pThis->core.CR));
2389 if (nCr.STP != pThis->core.cr.STP)
2390 {
2391 if (nCr.STP)
2392 {
2393 /* Stop the engine -- software reset. */
2394 pThis->core.cr.STP = 1;
2395 pThis->core.isr.RST = 1;
2396 }
2397 else
2398 {
2399 /* Clear the stop condition. */
2400 pThis->core.cr.STP = 0;
2401
2402 /* And possibly start up right away. */
2403 if (nCr.STA)
2404 pThis->core.cr.STA = 1;
2405
2406 /* The STA bit may have been set all along. */
2407 if (pThis->core.cr.STA)
2408 pThis->core.isr.RST = 0;
2409 }
2410
2411 /* Unblock receive thread if necessary, possibly drop any packets. */
2412 dp8390CoreKickReceive(pDevIns, pThis);
2413 }
2414 if (nCr.STA && !pThis->core.cr.STA)
2415 {
2416 /* Start the engine. It is not clearly documented but the STA bit is
2417 * sticky, and once it's set only a hard reset can clear it. Setting the
2418 * STP bit doesn't clear it.
2419 */
2420 pThis->core.cr.STA = 1;
2421 pThis->core.isr.RST = 0;
2422
2423 /* Unblock receive thread. */
2424 dp8390CoreKickReceive(pDevIns, pThis);
2425 }
2426 if (nCr.TXP && !pThis->core.cr.TXP)
2427 {
2428 /* Kick off a transmit. */
2429 pThis->core.cr.TXP = 1; /* Indicate transmit in progress. */
2430 dp8390CoreStartTransmit(pDevIns, pThis);
2431 }
2432
2433 /* It is not possible to write a zero (invalid value) to the RD bits. */
2434 if (nCr.RD == DP_CR_RDMA_INVL)
2435 nCr.RD = DP_CR_RDMA_ABRT;
2436
2437 if (nCr.RD != pThis->core.cr.RD)
2438 {
2439 /* Remote DMA state change. */
2440 if (nCr.RD & DP_CR_RDMA_ABRT)
2441 {
2442 /* Abort. */
2443 LogFunc(("RDMA Abort! RD=%d RSAR=%04X RBCR=%04X CRDA=%04X\n", nCr.RD, pThis->core.RSAR, pThis->core.RBCR, pThis->core.CRDA));
2444 }
2445 else if (nCr.RD == DP_CR_RDMA_SP)
2446 {
2447 DP_PKT_HDR header;
2448
2449 /* Read a packet header from memory at BNRY. */
2450 dpLocalRAMReadBuf(pThis, pThis->core.BNRY, sizeof(header), (uint8_t*)&header);
2451
2452 pThis->core.CRDA = RT_MAKE_U16(0, pThis->core.BNRY);
2453 pThis->core.RBCR = header.byte_cnt;
2454
2455 LogFunc(("RDMA SP: RD=%d RSAR=%04X RBCR=%04X CRDA=%04X\n", nCr.RD, pThis->core.RSAR, pThis->core.RBCR, pThis->core.CRDA));
2456 }
2457 else
2458 {
2459 /* Starting remote DMA read or write. */
2460 LogFunc(("RDMA: RD=%d RSAR=%04X RBCR=%04X\n", nCr.RD, pThis->core.RSAR, pThis->core.RBCR));
2461 }
2462 pThis->core.cr.RD = nCr.RD;
2463 /* NB: The current DMA address (CRDA) is not modified here. */
2464 }
2465 /* Set the page select bits. */
2466 pThis->core.cr.PS = nCr.PS;
2467
2468 return VINF_SUCCESS;
2469}
2470
2471static int dp8390CoreWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, int ofs, uint32_t val)
2472{
2473 int rc = VINF_SUCCESS;
2474 bool fUpdateIRQ = false;
2475
2476 Log2Func(("#%d: page=%d reg=%X val=%02X\n", pThis->iInstance, pThis->core.cr.PS, ofs, val));
2477
2478 /* Command Register exists in all pages. */
2479 if (ofs == DPR_CR)
2480 {
2481 rc = dp8390CoreWriteCR(pDevIns, pThis, val);
2482 }
2483 else if (pThis->core.cr.PS == 0)
2484 {
2485 switch (ofs)
2486 {
2487 case DPR_P0_W_PSTART:
2488 pThis->core.PSTART = val;
2489 pThis->core.CURR = val;
2490 break;
2491 case DPR_P0_W_PSTOP:
2492 pThis->core.PSTOP = val;
2493 break;
2494 case DPR_P0_BNRY:
2495 if (pThis->core.BNRY != val)
2496 {
2497 pThis->core.BNRY = val;
2498 /* Probably made more room in receive ring. */
2499 dp8390CoreKickReceive(pDevIns, pThis);
2500 }
2501 break;
2502 case DPR_P0_W_TPSR:
2503 pThis->core.TPSR = val;
2504 break;
2505 case DPR_P0_W_TBCR0:
2506 pThis->core.tbcr.TBCR0 = val;
2507 break;
2508 case DPR_P0_W_TBCR1:
2509 pThis->core.tbcr.TBCR1 = val;
2510 break;
2511 case DPR_P0_ISR:
2512 /* Bits are cleared by writing 1 to them, except for bit 7 (RST). */
2513 pThis->core.ISR &= ~val | RT_BIT(7);
2514 fUpdateIRQ = true;
2515 break;
2516 case DPR_P0_W_RSAR0:
2517 /* NE2000 ODI driver v2.12 detects card presence by writing RSAR0
2518 * and checking if CRDA0 changes to the same value.
2519 */
2520 pThis->core.rsar.RSAR0 = val;
2521 pThis->core.crda.CRDA0 = val;
2522 break;
2523 case DPR_P0_W_RSAR1:
2524 pThis->core.rsar.RSAR1 = val;
2525 pThis->core.crda.CRDA1 = val;
2526 break;
2527 case DPR_P0_W_RBCR0:
2528 pThis->core.rbcr.RBCR0 = val;
2529 break;
2530 case DPR_P0_W_RBCR1:
2531 pThis->core.rbcr.RBCR1 = val;
2532 break;
2533 case DPR_P0_W_RCR:
2534 pThis->core.RCR = val;
2535 pThis->core.rsr.DIS = pThis->core.rcr.MON;
2536 break;
2537 case DPR_P0_W_TCR:
2538 pThis->core.TCR = val;
2539 break;
2540 case DPR_P0_W_DCR:
2541 pThis->core.DCR = val;
2542 break;
2543 case DPR_P0_W_IMR:
2544 pThis->core.IMR = val & 0x7f; /* Don't let the high bit get set. */
2545 fUpdateIRQ = true;
2546 break;
2547 default:
2548 Assert(0);
2549 break;
2550 }
2551 }
2552 else if (pThis->core.cr.PS == 1)
2553 {
2554 /* Page 1 is easy, most registers are stored directly. */
2555 if (ofs == DPR_P1_CURR)
2556 {
2557 pThis->core.CURR = val;
2558 }
2559 else
2560 pThis->core.PG1[ofs] = val;
2561 }
2562 else if (pThis->core.cr.PS == 2)
2563 {
2564 switch (ofs)
2565 {
2566 case DPR_P2_W_CLDA0:
2567 pThis->core.clda.CLDA0 = val;
2568 break;
2569 case DPR_P2_W_CLDA1:
2570 pThis->core.clda.CLDA1 = val;
2571 break;
2572 case DPR_P2_RNXTPP:
2573 pThis->core.rnxtpp = val;
2574 break;
2575 case DPR_P2_LNXTPP:
2576 pThis->core.lnxtpp = val;
2577 break;
2578 case DPR_P2_ADRCU:
2579 case DPR_P2_ADRCL:
2580 /// @todo What are these?
2581 break;
2582 default:
2583 LogFunc(("Writing unimplemented register: Page 2, offset=%d, val=%02X!\n", ofs, val));
2584 break;
2585 }
2586 }
2587 else
2588 {
2589 /* Page 3 is undocumented and unimplemented. */
2590 LogFunc(("Writing page 3 register: offset=%d, val=%02X!\n", ofs, val));
2591 }
2592
2593 if (fUpdateIRQ)
2594 dp8390CoreUpdateIrq(pDevIns, pThis);
2595
2596 return rc;
2597}
2598
2599
2600static void neLocalRAMWrite8(PDPNICSTATE pThis, uint16_t addr, uint8_t val)
2601{
2602 if (pThis->uDevType == DEV_NE1000)
2603 {
2604 /* Only 14 bits of address are decoded. */
2605 addr &= 0x3fff;
2606 if (addr >= 0x2000)
2607 {
2608 /* Local RAM is mapped at 2000h-3FFFh. */
2609 addr -= 0x2000;
2610 pThis->abLocalRAM[addr] = val;
2611 }
2612 }
2613 else if (pThis->uDevType == DEV_NE2000)
2614 {
2615 /* Only 15 bits of address are decoded. */
2616 addr &= 0x7fff;
2617 if (addr >= 0x4000)
2618 {
2619 /* Local RAM is mapped at 4000h-7FFFh. */
2620 addr -= 0x4000;
2621 pThis->abLocalRAM[addr] = val;
2622 }
2623 }
2624 else
2625 {
2626 Assert(0);
2627 }
2628}
2629
2630
2631static void neLocalRAMWrite16(PDPNICSTATE pThis, uint16_t addr, uint16_t val)
2632{
2633 if (pThis->uDevType == DEV_NE2000)
2634 {
2635 /* Only 14 bits of address are decoded, word aligned. */
2636 addr &= 0x7ffe;
2637 if (addr >= 0x4000)
2638 {
2639 /* Local RAM is mapped at 4000h-7FFFh. */
2640 addr -= 0x4000;
2641 pThis->abLocalRAM[addr+0] = RT_LOBYTE(val);
2642 pThis->abLocalRAM[addr+1] = RT_HIBYTE(val);
2643 }
2644 }
2645 else
2646 {
2647 Assert(0);
2648 }
2649}
2650
2651
2652static uint8_t neLocalRAMRead8(PDPNICSTATE pThis, uint16_t addr)
2653{
2654 uint8_t val = 0xff;
2655
2656 if (pThis->uDevType == DEV_NE1000)
2657 {
2658 /* Only 14 bits of address are decoded. */
2659 addr &= 0x3fff;
2660 if (addr >= 0x2000)
2661 {
2662 /* Local RAM is mapped at 2000h-3FFFh. */
2663 addr -= 0x2000;
2664 val = pThis->abLocalRAM[addr];
2665 }
2666 else
2667 {
2668 /* The PROM is mapped below 2000h, effectively only 4 bits decoded.
2669 * NE1000 emulation uses top 16 bytes of the PROM.
2670 */
2671 val = pThis->aPROM[(addr & 0x0f) + 16]; /// @todo Use a constant
2672 }
2673 }
2674 else if (pThis->uDevType == DEV_NE2000)
2675 {
2676 /* Only 15 bits of address are decoded. */
2677 addr &= 0x7fff;
2678 if (addr >= 0x4000)
2679 {
2680 /* Local RAM is mapped at 4000h-7FFFh. */
2681 addr -= 0x4000;
2682 val = pThis->abLocalRAM[addr];
2683 }
2684 else
2685 {
2686 /* The PROM is mapped below 4000h, effectively only 4 bits decoded.
2687 * Address bits 1:4 from the bus are connected to address pins 0:3
2688 * on the PROM.
2689 */
2690 val = pThis->aPROM[(addr & 0x1f) >> 1]; /// @todo use a constant
2691 }
2692 }
2693 else
2694 {
2695 Assert(0);
2696 }
2697 return val;
2698}
2699
2700
2701static uint16_t neLocalRAMRead16(PDPNICSTATE pThis, uint16_t addr)
2702{
2703 uint16_t val = 0xffff;
2704
2705 if (pThis->uDevType == DEV_NE2000)
2706 {
2707 /* Only 14 bits of address are decoded, word aligned. */
2708 addr &= 0x7ffe;
2709 if (addr >= 0x4000)
2710 {
2711 /* Local RAM is mapped at 4000h-7FFFh. */
2712 addr -= 0x4000;
2713 val = RT_MAKE_U16(pThis->abLocalRAM[addr], pThis->abLocalRAM[addr+1]);
2714 }
2715 else
2716 {
2717 uint8_t uPromByte;
2718
2719 /* The PROM is mapped below 4000h, effectively only 4 bits decoded.
2720 * Address bits 1:4 from the bus are connected to address pins 0:3
2721 * on the PROM.
2722 */
2723 uPromByte = pThis->aPROM[(addr & 0x1f) >> 1];
2724 val = RT_MAKE_U16(uPromByte, uPromByte);
2725 }
2726 }
2727 else
2728 {
2729 Assert(0);
2730 }
2731 return val;
2732}
2733
2734
2735static int neDataPortWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint16_t val)
2736{
2737 /* Remote Write; ignored if Remote DMA command is not 'Write'. */
2738 if (pThis->core.cr.RD == DP_CR_RDMA_WR)
2739 {
2740 /// @todo Also do nothing if DCR.LAS set?
2741 if (pThis->core.dcr.WTS)
2742 {
2743 Log3Func(("RDMA16 write %04X to local addr %04X\n", val, pThis->core.CRDA));
2744 neLocalRAMWrite16(pThis, pThis->core.CRDA, val);
2745 }
2746 else
2747 {
2748 Log3Func(("RDMA8 write %02X to local addr %04X\n", val, pThis->core.CRDA));
2749 neLocalRAMWrite8(pThis, pThis->core.CRDA, val);
2750 }
2751 pThis->core.CRDA += 1 << pThis->core.dcr.WTS;
2752 if ((pThis->core.crda.CRDA1 == pThis->core.PSTOP) && (pThis->core.PSTOP != pThis->core.PSTART))
2753 {
2754 LogFunc(("RDMA wrap / write!! (CRDA=%04X PSTOP=%02X00 PSTART=%02X00)\n", pThis->core.CRDA, pThis->core.PSTOP, pThis->core.PSTART));
2755 Assert(!pThis->core.crda.CRDA0); /// @todo Can misalignment actually happen?
2756 pThis->core.crda.CRDA1 = pThis->core.PSTART;
2757 }
2758 pThis->core.RBCR -= 1;
2759
2760 /* Carefully decrement if WTS set so we don't overshoot and miss EOP. */
2761 if (pThis->core.dcr.WTS && pThis->core.RBCR)
2762 pThis->core.RBCR -= 1;
2763
2764 if (!pThis->core.RBCR)
2765 {
2766 LogFunc(("RDMA EOP / write\n"));
2767 pThis->core.isr.RDC = 1;
2768 pThis->core.cr.RD = 0;
2769 dp8390CoreUpdateIrq(pDevIns, pThis);
2770 }
2771 }
2772 return VINF_SUCCESS;
2773}
2774
2775
2776static uint16_t neDataPortRead(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
2777{
2778 uint16_t val = 0x1234;
2779
2780 /* Remote Read; ignored if Remote DMA command is not 'Read'. */
2781 if (pThis->core.cr.RD == DP_CR_RDMA_RD)
2782 {
2783 /// @todo Also do nothing if DCR.LAS set?
2784 if (pThis->core.dcr.WTS)
2785 {
2786 val = neLocalRAMRead16(pThis, pThis->core.CRDA);
2787 Log3Func(("RDMA16 read from local addr %04X: %04X\n", pThis->core.CRDA, val));
2788 }
2789 else
2790 {
2791 val = neLocalRAMRead8(pThis, pThis->core.CRDA);
2792 Log3Func(("RDMA8 read from local addr %04X: %02X\n", pThis->core.CRDA, val));
2793 }
2794 pThis->core.CRDA += 1 << pThis->core.dcr.WTS;
2795 /// @todo explain that PSTOP=PSTART check is only to reduce logging/busywork
2796 if ((pThis->core.crda.CRDA1 == pThis->core.PSTOP) && (pThis->core.PSTOP != pThis->core.PSTART))
2797 {
2798 Log3Func(("RDMA wrap / read (CRDA=%04X PSTOP=%02X00 PSTART=%02X00)\n", pThis->core.CRDA, pThis->core.PSTOP, pThis->core.PSTART));
2799 Assert(!pThis->core.crda.CRDA0); /// @todo can misalignment happen?
2800 pThis->core.crda.CRDA1 = pThis->core.PSTART;
2801 }
2802 pThis->core.RBCR -= 1;
2803
2804 /* Carefully decrement if WTS set so we don't overshoot and miss EOP. */
2805 if (pThis->core.dcr.WTS && pThis->core.RBCR)
2806 pThis->core.RBCR -= 1;
2807
2808 if (!pThis->core.RBCR)
2809 {
2810 LogFunc(("RDMA EOP / read\n"));
2811 pThis->core.isr.RDC = 1;
2812 pThis->core.cr.RD = 0;
2813 dp8390CoreUpdateIrq(pDevIns, pThis);
2814 }
2815 }
2816 return val;
2817}
2818
2819
2820static int neResetPortWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
2821{
2822 LogFlowFunc(("\n"));
2823 dp8390CoreReset(pDevIns, pThis);
2824 return VINF_SUCCESS;
2825}
2826
2827
2828static int dpNeIoWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr, uint32_t val)
2829{
2830 int reg = addr & 0x0f;
2831 int rc = VINF_SUCCESS;
2832
2833 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
2834
2835 /* The NE2000 has 8 bytes of data port followed by 8 bytes of reset port.
2836 * In contrast, the NE1000 has 4 bytes of data port followed by 4 bytes
2837 * of reset port, aliased twice within the 16-byte range.
2838 */
2839 if (pThis->uDevType == DEV_NE2000)
2840 reg >>= 1;
2841 if (reg & 0x04)
2842 rc = neResetPortWrite(pDevIns, pThis);
2843 else
2844 rc = neDataPortWrite(pDevIns, pThis, val);
2845
2846 return rc;
2847}
2848
2849
2850static uint32_t neIoRead(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr)
2851{
2852 uint32_t val = UINT32_MAX;
2853 int reg = addr & 0x0f;
2854
2855 /* The NE2000 has 8 bytes of data port followed by 8 bytes of reset port.
2856 * In contrast, the NE1000 has 4 bytes of data port followed by 4 bytes
2857 * of reset port, aliased twice within the 16-byte range.
2858 */
2859 if (pThis->uDevType == DEV_NE2000)
2860 reg >>= 1;
2861 if (reg & 0x04)
2862 val = 0x52; /// @todo Check what really happens
2863 else
2864 val = neDataPortRead(pDevIns, pThis);
2865
2866 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
2867 return val;
2868}
2869
2870
2871static int wdIoWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr, uint32_t val)
2872{
2873 int reg = addr & 0xf;
2874 int rc = VINF_SUCCESS;
2875 union {
2876 uint8_t nCTRL1;
2877 WD_CTRL1 nCtrl1;
2878 };
2879 union {
2880 uint8_t nCTRL2;
2881 WD_CTRL2 nCtrl2;
2882 };
2883
2884 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
2885
2886 switch (reg)
2887 {
2888 case WDR_CTRL1:
2889 nCTRL1 = val;
2890 if (nCtrl1.MEME != pThis->ctrl1.MEME)
2891 {
2892 LogFunc(("CTRL1.MEME=%u\n", nCtrl1.MEME));
2893 pThis->ctrl1.MEME = nCtrl1.MEME;
2894 }
2895 if (nCtrl1.RESET)
2896 {
2897 dp8390CoreReset(pDevIns, pThis);
2898 pThis->CTRL1 = 0;
2899 }
2900 break;
2901 case WDR_CTRL2:
2902 /* NYI. */
2903 nCTRL2 = val;
2904 if (nCTRL2 != pThis->CTRL2)
2905 {
2906 LogFunc(("CTRL2=%02X, new=%02X\n", pThis->CTRL2, nCTRL2));
2907 pThis->CTRL2 = nCTRL2;
2908 }
2909 break;
2910 default:
2911 /* Most of the WD registers are read-only. */
2912 break;
2913 }
2914
2915 return rc;
2916}
2917
2918
2919static uint32_t wdIoRead(PDPNICSTATE pThis, uint32_t addr)
2920{
2921 uint32_t val = UINT32_MAX;
2922 int reg = addr & 0x0f;
2923
2924 if (reg >= WDR_PROM)
2925 {
2926 val = pThis->aPROM[reg & 7];
2927 }
2928 else
2929 {
2930 if (pThis->uDevType == DEV_WD8013)
2931 {
2932 switch (reg)
2933 {
2934 case WDR_CTRL1:
2935 val = pThis->CTRL1;
2936 break;
2937 case WDR_ATDET:
2938 val = pThis->uDevType == DEV_WD8013 ? 1 : 0;
2939 break;
2940 case WDR_IOBASE:
2941 val = pThis->aPROM[WDR_IOBASE]; //val = pThis->IOPortBase >> 5;
2942 break;
2943 case WDR_CTRL2:
2944 val = pThis->CTRL2;
2945 break;
2946 case WDR_JP:
2947 val = 0xa0;
2948 break;
2949 default:
2950 val = 0x00; /// @todo What should it be really?
2951 break;
2952 }
2953 }
2954 else
2955 {
2956 /* Old WD adapters (including 8003E) aliased the PROM for
2957 * unimplemented control register reads.
2958 */
2959 switch (reg)
2960 {
2961 case WDR_CTRL2:
2962 val = 1; //pThis->CTRL2;
2963 break;
2964 case WDR_JP:
2965 val = 0xa0;
2966 break;
2967 default:
2968 val = pThis->aPROM[reg & 7];
2969 break;
2970 }
2971 }
2972
2973 }
2974
2975 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
2976 return val;
2977}
2978
2979
2980static uint8_t elGetIrqFromIdcfr(uint8_t val)
2981{
2982 union {
2983 uint8_t IDCFR;
2984 EL_IDCFR idcfr;
2985 };
2986 uint8_t irq = 0;
2987
2988 IDCFR = val;
2989
2990 /* Lowest set IRQ bit wins (might not match hardware).
2991 * NB: It is valid to not enable any IRQ line!
2992 */
2993 if (idcfr.irq2)
2994 irq = 2;
2995 else if (idcfr.irq3)
2996 irq = 3;
2997 else if (idcfr.irq4)
2998 irq = 4;
2999 else if (idcfr.irq5)
3000 irq = 5;
3001
3002 return irq;
3003}
3004
3005static uint8_t elGetDrqFromIdcfr(uint8_t val)
3006{
3007 union {
3008 uint8_t IDCFR;
3009 EL_IDCFR idcfr;
3010 };
3011 uint8_t drq = 0;
3012
3013 IDCFR = val;
3014
3015 /* Lowest set DRQ bit wins; it is valid to not set any. */
3016 if (idcfr.drq1)
3017 drq = 1;
3018 else if (idcfr.drq2)
3019 drq = 2;
3020 else if (idcfr.drq3)
3021 drq = 3;
3022
3023 return drq;
3024}
3025
3026static void elWriteIdcfr(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PEL_GA pGa, uint8_t val)
3027{
3028 uint8_t uOldIrq = pThis->uIsaIrq;
3029 uint8_t uNewIrq;
3030 uint8_t uOldDrq = pThis->uElIsaDma;
3031 uint8_t uNewDrq;
3032
3033 /* If the IRQ is currently active, have to switch it. */
3034 uNewIrq = elGetIrqFromIdcfr(val);
3035 if (uOldIrq != uNewIrq)
3036 {
3037 LogFunc(("#%d Switching IRQ=%d -> IRQ=%d\n", pThis->iInstance, uOldIrq, uNewIrq));
3038 if (pThis->fNicIrqActive)
3039 {
3040 /* This probably isn't supposed to happen. */
3041 LogFunc(("#%d Moving active IRQ!\n", pThis->iInstance));
3042 if (uOldIrq)
3043 PDMDevHlpISASetIrq(pDevIns, uOldIrq, 0);
3044 if (uNewIrq)
3045 PDMDevHlpISASetIrq(pDevIns, uNewIrq, 1);
3046 }
3047 pThis->uIsaIrq = uNewIrq;
3048 }
3049
3050 /* And now the same dance for DMA. */
3051 uNewDrq = elGetDrqFromIdcfr(val);
3052 if (uOldDrq != uNewDrq)
3053 {
3054 /// @todo We can't really move the DRQ, what can we do?
3055 LogFunc(("#%d Switching DRQ=%d -> DRQ=%d\n", pThis->iInstance, uOldDrq, uNewDrq));
3056 pThis->uElIsaDma = uNewDrq;
3057 }
3058
3059 pGa->IDCFR = val;
3060}
3061
3062
3063static void elWriteGacfr(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PEL_GA pGa, uint8_t val)
3064{
3065 union {
3066 uint8_t nGACFR;
3067 GA_GACFR nGacfr;
3068 };
3069
3070 nGACFR = val;
3071
3072 if (nGacfr.nim != pGa->gacfr.nim)
3073 {
3074 /// @todo Should we just run UpdateInterrupts?
3075 if (pThis->fNicIrqActive && !nGacfr.nim)
3076 {
3077 LogFunc(("#%d: Unmasking active IRQ!\n", pThis->iInstance));
3078 PDMDevHlpISASetIrq(pDevIns, pThis->uIsaIrq, 1);
3079 }
3080 else if (pThis->fNicIrqActive && nGacfr.nim)
3081 {
3082 LogFunc(("#%d: Masking active IRQ\n", pThis->iInstance));
3083 PDMDevHlpISASetIrq(pDevIns, pThis->uIsaIrq, 0);
3084 }
3085 }
3086
3087 /// @todo rsel/mbs bit change?
3088 if (nGacfr.rsel != pGa->gacfr.rsel)
3089 {
3090 LogFunc(("#%d: rsel=%u mbs=%u\n", pThis->iInstance, nGacfr.rsel, nGacfr.mbs));
3091 }
3092
3093 pGa->GACFR = nGACFR;
3094}
3095
3096
3097static void elSoftReset(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
3098{
3099 PEL_GA pGa = &pThis->ga;
3100
3101 LogFlow(("Resetting ASIC GA\n"));
3102 /* Most GA registers are zeroed. */
3103 pGa->PSTR = pGa->PSPR = 0;
3104 pGa->DQTR = 0;
3105 elWriteGacfr(pDevIns, pThis, pGa, 0);
3106 pGa->STREG = ELNKII_GA_REV;
3107 pGa->VPTR0 = pGa->VPTR1 = pGa->VPTR2 = 0;
3108 pGa->DALSB = pGa->DAMSB = 0;
3109 elWriteIdcfr(pDevIns, pThis, pGa, 0);
3110 pGa->GACR = 0x0B; /* Low bit set = in reset state. */
3111 pGa->fGaIrq = false;
3112
3113 /* Reset the NIC core. */
3114 dp8390CoreReset(pDevIns, pThis);
3115}
3116
3117
3118static int elWriteGacr(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PEL_GA pGa, uint8_t val)
3119{
3120 union {
3121 uint8_t nGACR;
3122 GA_GACR nGacr;
3123 };
3124
3125 nGACR = val;
3126
3127 if (nGacr.rst != pGa->gacr.rst)
3128 {
3129 /* When going out of reset, only clear the rst bit. 3C503 diagnostics checks for this. */
3130 if (nGacr.rst)
3131 elSoftReset(pDevIns, pThis);
3132 else
3133 pGa->gacr.rst = 0;
3134 }
3135 else
3136 {
3137#ifdef IN_RING0
3138 /* Force a trip to R3. */
3139 if (pThis->uElIsaDma == pThis->uIsaDma)
3140 return VINF_IOM_R3_IOPORT_WRITE;
3141#endif
3142
3143 /* Make the data registers "ready" as long as transfers are started. */
3144 if (nGacr.start)
3145 {
3146 pGa->cdadr.cdadr_lsb = pGa->DALSB;
3147 pGa->cdadr.cdadr_msb = pGa->DAMSB;
3148 LogFunc(("DMA started, ddir=%u, cdadr=%04X\n", pGa->gacr.ddir, pGa->CDADR));
3149 pGa->streg.dprdy = 1;
3150 pGa->streg.dip = 1;
3151 pGa->streg.dtc = 0;
3152 }
3153 else
3154 {
3155 pGa->streg.dprdy = 0;
3156 pGa->streg.dip = 0;
3157 }
3158
3159 /* Only do anything if the software configured DMA channel matches the emulation config. */
3160 if (pThis->uElIsaDma == pThis->uIsaDma)
3161 {
3162#ifdef IN_RING3
3163 PDMDevHlpDMASetDREQ(pDevIns, pThis->uIsaDma, pGa->streg.dprdy);
3164 if (pGa->streg.dprdy)
3165 PDMDevHlpDMASchedule(pDevIns);
3166 LogFunc(("#%d: DREQ for channel %u set to %u\n", pThis->iInstance, pThis->uIsaDma, pGa->streg.dprdy));
3167#else
3168 /* Must not get here. */
3169 Assert(0);
3170#endif
3171 }
3172
3173 pGa->GACR = nGACR;
3174 LogFunc(("GACR=%02X ealo=%u eahi=%u\n", pGa->GACR, pGa->gacr.ealo, pGa->gacr.eahi));
3175 }
3176
3177 return VINF_SUCCESS;
3178}
3179
3180
3181static int elGaDataWrite(PDPNICSTATE pThis, PEL_GA pGa, uint16_t val)
3182{
3183 /* Data write; ignored if not started and in "download" mode. */
3184 if (pGa->gacr.start && pGa->gacr.ddir)
3185 {
3186 uint16_t addr = pGa->CDADR;
3187
3188 addr &= 0x3fff;
3189 if (addr >= 0x2000)
3190 {
3191 /* Local RAM is mapped at 2000h-3FFFh. */
3192 addr -= 0x2000;
3193 pThis->abLocalRAM[addr] = val;
3194 }
3195
3196 pGa->CDADR++;
3197 /// @todo Does this really apply to writes or only reads?
3198 if ((pGa->cdadr.cdadr_msb == pGa->PSPR) && (pGa->PSPR != pGa->PSTR))
3199 {
3200 LogFunc(("GA DMA wrap / write!! (cdadr=%04X PSPR=%02X00 PSTR=%02X00)\n", pGa->CDADR, pGa->PSPR, pGa->PSTR));
3201 pGa->cdadr.cdadr_msb = pGa->PSTR;
3202 }
3203 }
3204 return VINF_SUCCESS;
3205}
3206
3207
3208static uint8_t elGaDataRead(PDPNICSTATE pThis, PEL_GA pGa)
3209{
3210 uint8_t val = 0xcd;
3211
3212 /* Data read; ignored if not started and in "upload" mode. */
3213 if (pGa->gacr.start && !pGa->gacr.ddir)
3214 {
3215 uint16_t addr = pGa->CDADR;
3216
3217 addr &= 0x3fff;
3218 if (addr >= 0x2000)
3219 {
3220 /* Local RAM is mapped at 2000h-3FFFh. */
3221 addr -= 0x2000;
3222 val = pThis->abLocalRAM[addr];
3223 }
3224
3225 pGa->CDADR++;
3226 if ((pGa->cdadr.cdadr_msb == pGa->PSPR) && (pGa->PSPR != pGa->PSTR))
3227 {
3228 LogFunc(("GA DMA wrap / read!! (cdadr=%04X PSPR=%02X00 PSTR=%02X00)\n", pGa->CDADR, pGa->PSPR, pGa->PSTR));
3229 pGa->cdadr.cdadr_msb = pGa->PSTR;
3230 }
3231 }
3232 return val;
3233}
3234
3235
3236static int elGaIoWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr, uint32_t val)
3237{
3238 int reg = addr & 0xf;
3239 int rc = VINF_SUCCESS;
3240 PEL_GA pGa = &pThis->ga;
3241
3242 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
3243
3244 switch (reg)
3245 {
3246 case GAR_PSTR:
3247 pGa->PSTR = val;
3248 break;
3249 case GAR_PSPR:
3250 pGa->PSPR = val;
3251 break;
3252 case GAR_DQTR:
3253 pGa->DQTR = val;
3254 break;
3255 case GAR_GACFR:
3256 elWriteGacfr(pDevIns, pThis, pGa, val);
3257 break;
3258 case GAR_GACR:
3259 rc = elWriteGacr(pDevIns, pThis, pGa, val);
3260 break;
3261 case GAR_STREG:
3262 /* Writing anything to STREG clears ASIC interrupt. */
3263 pThis->ga.streg.dtc = 0;
3264 pThis->ga.fGaIrq = false;
3265 dp8390CoreUpdateIrq(pDevIns, pThis);
3266 break;
3267 case GAR_IDCFR:
3268 elWriteIdcfr(pDevIns, pThis, pGa, val);
3269 break;
3270 case GAR_DAMSB:
3271 pGa->DAMSB = val;
3272 break;
3273 case GAR_DALSB:
3274 pGa->DALSB = val;
3275 break;
3276 case GAR_VPTR2:
3277 pGa->VPTR2 = val;
3278 break;
3279 case GAR_VPTR1:
3280 pGa->VPTR1 = val;
3281 break;
3282 case GAR_VPTR0:
3283 pGa->VPTR0 = val;
3284 break;
3285 case GAR_RFMSB:
3286 case GAR_RFLSB:
3287 elGaDataWrite(pThis, pGa, val);
3288 break;
3289 case GAR_R_BCFR:
3290 case GAR_R_PCFR:
3291 /* Read-only registers, ignored. */
3292 break;
3293 default:
3294 Assert(0);
3295 break;
3296 }
3297
3298 return rc;
3299}
3300
3301
3302static uint32_t elGaIoRead(PDPNICSTATE pThis, uint32_t addr)
3303{
3304 uint32_t val = UINT32_MAX;
3305 int reg = addr & 0x0f;
3306 PEL_GA pGa = &pThis->ga;
3307
3308 switch (reg)
3309 {
3310 case GAR_PSTR:
3311 val = pGa->PSTR;
3312 break;
3313 case GAR_PSPR:
3314 val = pGa->PSPR;
3315 break;
3316 case GAR_DQTR:
3317 val = pGa->DQTR;
3318 break;
3319 case GAR_R_BCFR:
3320 val = pGa->BCFR;
3321 break;
3322 case GAR_R_PCFR:
3323 val = pGa->PCFR;
3324 break;
3325 case GAR_GACFR:
3326 val = pGa->GACFR;
3327 break;
3328 case GAR_GACR:
3329 val = pGa->GACR;
3330 break;
3331 case GAR_STREG:
3332 val = pGa->STREG;
3333 break;
3334 case GAR_IDCFR:
3335 val = pGa->IDCFR;
3336 break;
3337 case GAR_DAMSB:
3338 val = pGa->DAMSB;
3339 break;
3340 case GAR_DALSB:
3341 val = pGa->DALSB;
3342 break;
3343 case GAR_VPTR2:
3344 val = pGa->VPTR2;
3345 break;
3346 case GAR_VPTR1:
3347 val = pGa->VPTR1;
3348 break;
3349 case GAR_VPTR0:
3350 val = pGa->VPTR0;
3351 break;
3352 case GAR_RFMSB:
3353 case GAR_RFLSB:
3354 val = elGaDataRead(pThis, pGa);
3355 break;
3356 default:
3357 Assert(0);
3358 break;
3359 }
3360
3361 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
3362 return val;
3363}
3364
3365
3366/**
3367 * @callback_method_impl{FNIOMIOPORTIN}
3368 */
3369static DECLCALLBACK(VBOXSTRICTRC)
3370neIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3371{
3372 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3373 int rc = VINF_SUCCESS;
3374 int reg = Port & 0xf;
3375 uint8_t u8Lo, u8Hi = 0;
3376 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
3377 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3378 RT_NOREF_PV(pvUser);
3379
3380 switch (cb)
3381 {
3382 case 1:
3383 *pu32 = neIoRead(pDevIns, pThis, reg);
3384 break;
3385 case 2:
3386 /* Manually split word access if necessary if it's an NE1000. Perhaps overkill. */
3387 if (pThis->uDevType == DEV_NE1000)
3388 {
3389 u8Lo = neIoRead(pDevIns, pThis, reg);
3390 if (reg < 0xf) // This logic is not entirely accurate (wraparound).
3391 u8Hi = neIoRead(pDevIns, pThis, reg + 1);
3392 *pu32 = RT_MAKE_U16(u8Lo, u8Hi);
3393 }
3394 else
3395 *pu32 = neIoRead(pDevIns, pThis, reg);
3396 break;
3397 default:
3398 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3399 "neIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3400 Port, cb);
3401 }
3402
3403 Log2Func(("#%d: NE Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
3404 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3405 return rc;
3406}
3407
3408
3409/**
3410 * @callback_method_impl{FNIOMIOPORTIN}
3411 */
3412static DECLCALLBACK(VBOXSTRICTRC)
3413wdIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3414{
3415 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3416 int rc = VINF_SUCCESS;
3417 int reg = Port & 0xf;
3418 uint8_t u8Lo, u8Hi = 0;
3419 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
3420 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3421 RT_NOREF_PV(pvUser);
3422
3423 switch (cb)
3424 {
3425 case 1:
3426 *pu32 = wdIoRead(pThis, reg);
3427 break;
3428 case 2:
3429 /* Manually split word access. */
3430 u8Lo = wdIoRead(pThis, reg);
3431 if (reg < 0xf) // This logic is not entirely accurate (wraparound).
3432 u8Hi = wdIoRead(pThis, reg + 1);
3433 *pu32 = RT_MAKE_U16(u8Lo, u8Hi);
3434 break;
3435 default:
3436 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3437 "wdIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3438 Port, cb);
3439 }
3440
3441 Log2Func(("#%d: WD Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
3442 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3443 return rc;
3444}
3445
3446
3447/**
3448 * @callback_method_impl{FNIOMIOPORTIN}
3449 */
3450static DECLCALLBACK(VBOXSTRICTRC)
3451elIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3452{
3453 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3454 int rc = VINF_SUCCESS;
3455 int reg = Port & 0xf;
3456 uint8_t u8Lo, u8Hi = 0;
3457 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
3458 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3459 RT_NOREF_PV(pvUser);
3460
3461 switch (cb)
3462 {
3463 case 1:
3464 *pu32 = elGaIoRead(pThis, reg);
3465 break;
3466 case 2:
3467 /* Manually split word access. */
3468 u8Lo = elGaIoRead(pThis, reg);
3469 if (reg < 0xf) // This logic is not entirely accurate (wraparound).
3470 u8Hi = elGaIoRead(pThis, reg + 1);
3471 *pu32 = RT_MAKE_U16(u8Lo, u8Hi);
3472 break;
3473 default:
3474 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3475 "elIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3476 Port, cb);
3477 }
3478
3479 Log2Func(("#%d: EL Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
3480 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3481 return rc;
3482}
3483
3484
3485/**
3486 * @callback_method_impl{FNIOMIOPORTIN}
3487 */
3488static DECLCALLBACK(VBOXSTRICTRC)
3489dp8390CoreIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
3490{
3491 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3492 int rc = VINF_SUCCESS;
3493 int reg = Port & 0xf;
3494 uint8_t u8Lo, u8Hi;
3495 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIORead), a);
3496 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3497 RT_NOREF_PV(pvUser);
3498
3499 switch (cb)
3500 {
3501 case 1:
3502 *pu32 = dp8390CoreRead(pDevIns, pThis, reg);
3503 break;
3504 case 2:
3505 /* Manually split word access. */
3506 u8Lo = dp8390CoreRead(pDevIns, pThis, reg + 0);
3507 /* This logic is not entirely accurate. */
3508 if (reg < 0xf)
3509 u8Hi = dp8390CoreRead(pDevIns, pThis, reg + 1);
3510 else
3511 u8Hi = 0;
3512 *pu32 = RT_MAKE_U16(u8Lo, u8Hi);
3513 break;
3514 default:
3515 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3516 "dp8390CoreIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3517 Port, cb);
3518 }
3519
3520 Log2Func(("#%d: Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
3521 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3522 return rc;
3523}
3524
3525
3526/**
3527 * @callback_method_impl{FNIOMIOPORTOUT}
3528 */
3529static DECLCALLBACK(VBOXSTRICTRC)
3530neIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3531{
3532 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3533 int rc = VINF_SUCCESS;
3534 int reg = Port & 0xf;
3535 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3536 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3537 RT_NOREF_PV(pvUser);
3538
3539 switch (cb)
3540 {
3541 case 1:
3542 rc = dpNeIoWrite(pDevIns, pThis, Port, RT_LOBYTE(u32));
3543 break;
3544 case 2:
3545 /* Manually split word access if necessary. */
3546 if (pThis->uDevType == DEV_NE2000)
3547 {
3548 rc = dpNeIoWrite(pDevIns, pThis, Port, RT_LOWORD(u32));
3549 }
3550 else
3551 {
3552 rc = dpNeIoWrite(pDevIns, pThis, reg + 0, RT_LOBYTE(u32));
3553 if (RT_SUCCESS(rc) && (reg < 0xf))
3554 rc = dpNeIoWrite(pDevIns, pThis, reg + 1, RT_HIBYTE(u32));
3555 }
3556 break;
3557 default:
3558 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3559 "neIOPortWrite: unsupported operation size: offset=%#10x cb=%u\n",
3560 Port, cb);
3561 }
3562
3563 Log2Func(("#%d: NE Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, u32, cb, rc));
3564 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3565 return rc;
3566}
3567
3568
3569/**
3570 * @callback_method_impl{FNIOMIOPORTOUT}
3571 */
3572static DECLCALLBACK(VBOXSTRICTRC)
3573wdIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3574{
3575 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3576 int rc = VINF_SUCCESS;
3577 int reg = Port & 0xf;
3578 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3579 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3580 RT_NOREF_PV(pvUser);
3581
3582 switch (cb)
3583 {
3584 case 1:
3585 rc = wdIoWrite(pDevIns, pThis, Port, RT_LOBYTE(u32));
3586 break;
3587 case 2:
3588 /* Manually split word access. */
3589 rc = wdIoWrite(pDevIns, pThis, reg + 0, RT_LOBYTE(u32));
3590 if (RT_SUCCESS(rc) && (reg < 0xf))
3591 rc = wdIoWrite(pDevIns, pThis, reg + 1, RT_HIBYTE(u32));
3592 break;
3593 default:
3594 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3595 "wdIOPortWrite: unsupported operation size: offset=%#10x cb=%u\n",
3596 Port, cb);
3597 }
3598
3599 Log2Func(("#%d: WD Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, u32, cb, rc));
3600 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3601 return rc;
3602}
3603
3604
3605/**
3606 * @callback_method_impl{FNIOMIOPORTOUT}
3607 */
3608static DECLCALLBACK(VBOXSTRICTRC)
3609elIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3610{
3611 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3612 int rc = VINF_SUCCESS;
3613 int reg = Port & 0xf;
3614 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3615 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3616 RT_NOREF_PV(pvUser);
3617
3618 switch (cb)
3619 {
3620 case 1:
3621 rc = elGaIoWrite(pDevIns, pThis, Port, RT_LOBYTE(u32));
3622 break;
3623 case 2:
3624 /* Manually split word access. */
3625 rc = elGaIoWrite(pDevIns, pThis, reg + 0, RT_LOBYTE(u32));
3626 if (RT_SUCCESS(rc) && (reg < 0xf))
3627 rc = elGaIoWrite(pDevIns, pThis, reg + 1, RT_HIBYTE(u32));
3628 break;
3629 default:
3630 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3631 "elIOPortWrite: unsupported operation size: offset=%#10x cb=%u\n",
3632 Port, cb);
3633 }
3634
3635 Log2Func(("#%d: EL Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, u32, cb, rc));
3636 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3637 return rc;
3638}
3639
3640
3641/**
3642 * @callback_method_impl{FNIOMIOPORTOUT}
3643 */
3644static DECLCALLBACK(VBOXSTRICTRC)
3645dp8390CoreIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
3646{
3647 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3648 int rc = VINF_SUCCESS;
3649 int reg = Port & 0xf;
3650 STAM_PROFILE_ADV_START(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3651 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
3652 RT_NOREF_PV(pvUser);
3653
3654 switch (cb)
3655 {
3656 case 1:
3657 rc = dp8390CoreWrite(pDevIns, pThis, reg, RT_LOBYTE(u32));
3658 break;
3659 case 2:
3660 /* Manually split word access. */
3661 rc = dp8390CoreWrite(pDevIns, pThis, reg + 0, RT_LOBYTE(u32));
3662 if (!RT_SUCCESS(rc))
3663 break;
3664 rc = dp8390CoreWrite(pDevIns, pThis, reg + 1, RT_HIBYTE(u32));
3665 break;
3666 default:
3667 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
3668 "dp8390CoreIOPortWrite: unsupported operation size: offset=%#10x cb=%u\n",
3669 Port, cb);
3670 }
3671
3672 Log2Func(("#%d: Port=%RTiop u32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, u32, cb, rc));
3673 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIOWrite), a);
3674 return rc;
3675}
3676
3677
3678#if 0
3679/**
3680 * @callback_method_impl{FNIOMMMIONEWFILL,
3681 * Local RAM write hook\, to be called from IOM. This is the advanced version of
3682 * wdMemWrite function.}
3683 */
3684static DECLCALLBACK(VBOXSTRICTRC)
3685dpWdMmioFill(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, uint32_t u32Item, unsigned cbItem, unsigned cItems)
3686{
3687 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3688 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
3689
3690 !!
3691 return VINF_SUCCESS
3692}
3693#endif
3694
3695
3696/**
3697 * @callback_method_impl{FNIOMMMIONEWREAD,
3698 * Local RAM read hook\, to be called from IOM.}
3699 */
3700static DECLCALLBACK(VBOXSTRICTRC) wdMemRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
3701{
3702 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3703 uint8_t *pbData = (uint8_t *)pv;
3704 NOREF(pvUser);
3705
3706// STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3707 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
3708
3709 if (pThis->ctrl1.MEME)
3710 {
3711 Log3Func(("#%d: Reading %u bytes from address %X: [%.*Rhxs]\n", pThis->iInstance, cb, off, cb, &pThis->abLocalRAM[off & DPNIC_MEM_MASK]));
3712 while (cb-- > 0)
3713 *pbData++ = pThis->abLocalRAM[off++ & DPNIC_MEM_MASK];
3714 }
3715 else
3716 memset(pv, 0xff, cb);
3717
3718// STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryRead), a);
3719 return VINF_SUCCESS;
3720}
3721
3722/**
3723 * @callback_method_impl{FNIOMMMIONEWWRITE,
3724 * Local RAM write hook\, to be called from IOM.}
3725 */
3726static DECLCALLBACK(VBOXSTRICTRC) wdMemWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3727{
3728 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3729 uint8_t const *pbSrc = (uint8_t const *)pv;
3730 NOREF(pvUser);
3731
3732// STAM_PROFILE_START(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3733 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
3734
3735 if (pThis->ctrl1.MEME)
3736 {
3737 Log3Func(("#%d: Writing %u bytes to address %X: [%.*Rhxs]\n", pThis->iInstance, cb, off, cb, pbSrc));
3738 while (cb-- > 0)
3739 pThis->abLocalRAM[off++ & DPNIC_MEM_MASK] = *pbSrc++;
3740 }
3741
3742// STAM_PROFILE_STOP(&pThis->CTX_MID_Z(Stat,MemoryWrite), a);
3743 return VINF_SUCCESS;
3744}
3745
3746
3747/**
3748 * @callback_method_impl{FNIOMMMIONEWREAD,
3749 * Local RAM read hook\, to be called from IOM.}
3750 */
3751static DECLCALLBACK(VBOXSTRICTRC) elMemRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
3752{
3753 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3754 uint8_t *pbData = (uint8_t *)pv;
3755 NOREF(pvUser);
3756
3757 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
3758
3759 if (pThis->ga.gacfr.rsel)
3760 {
3761 Log3Func(("#%d: Reading %u bytes from address %X\n", pThis->iInstance, cb, off));
3762 while (cb-- > 0)
3763 *pbData++ = pThis->abLocalRAM[off++ & DPNIC_MEM_MASK];
3764 }
3765 else
3766 {
3767 Log3Func(("#%d: Ignoring read of %u bytes from address %X\n", pThis->iInstance, cb, off));
3768 memset(pv, 0xff, cb);
3769 }
3770 return VINF_SUCCESS;
3771}
3772
3773
3774/**
3775 * @callback_method_impl{FNIOMMMIONEWWRITE,
3776 * Local RAM write hook\, to be called from IOM.}
3777 */
3778static DECLCALLBACK(VBOXSTRICTRC) elMemWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
3779{
3780 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3781 uint8_t const *pbSrc = (uint8_t const *)pv;
3782 NOREF(pvUser);
3783
3784 Assert(PDMDevHlpCritSectIsOwner(pDevIns, pDevIns->CTX_SUFF(pCritSectRo)));
3785
3786 if (pThis->ga.gacfr.rsel)
3787 {
3788 Log3Func(("#%d: Writing %u bytes to address %X\n", pThis->iInstance, cb, off));
3789 while (cb-- > 0)
3790 pThis->abLocalRAM[off++ & DPNIC_MEM_MASK] = *pbSrc++;
3791 }
3792 else
3793 {
3794 Log3Func(("#%d: Ignoring write of %u bytes to address %X\n", pThis->iInstance, cb, off));
3795 }
3796 return VINF_SUCCESS;
3797}
3798
3799
3800#ifdef IN_RING3
3801
3802/* Shamelessly stolen from DevDMA.cpp */
3803
3804/* Test the decrement bit of mode register. */
3805#define IS_MODE_DEC(c) ((c) & 0x20)
3806/* Test the auto-init bit of mode register. */
3807#define IS_MODE_AI(c) ((c) & 0x10)
3808/* Extract the transfer type bits of mode register. */
3809#define GET_MODE_XTYP(c) (((c) & 0x0c) >> 2)
3810
3811/* DMA transfer modes. */
3812enum {
3813 DMODE_DEMAND, /* Demand transfer mode. */
3814 DMODE_SINGLE, /* Single transfer mode. */
3815 DMODE_BLOCK, /* Block transfer mode. */
3816 DMODE_CASCADE /* Cascade mode. */
3817};
3818
3819/* DMA transfer types. */
3820enum {
3821 DTYPE_VERIFY, /* Verify transfer type. */
3822 DTYPE_WRITE, /* Write transfer type. */
3823 DTYPE_READ, /* Read transfer type. */
3824 DTYPE_ILLEGAL /* Undefined. */
3825};
3826
3827static DECLCALLBACK(uint32_t) elnk3R3DMAXferHandler(PPDMDEVINS pDevIns, void *opaque,
3828 unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
3829{
3830 PDPNICSTATE pThis = (PDPNICSTATE)opaque;
3831 int dma_mode;
3832 int dma_type;
3833 uint16_t cbToXfer;
3834 uint32_t cbXferred = 0;
3835 uint16_t uDmaAddr;
3836 int rc;
3837
3838 /*
3839 * The 3C503 EtherLink II uses DMA as an alternative to shared RAM
3840 * or PIO. The Gate Array tracks its own current DMA address within
3841 * the adapter's local address space.
3842 */
3843 dma_mode = PDMDevHlpDMAGetChannelMode(pDevIns, pThis->uIsaDma);
3844 dma_type = GET_MODE_XTYP(dma_mode);
3845 uDmaAddr = pThis->ga.CDADR;
3846 cbToXfer = dma_len;
3847 LogFlowFunc(("dma_mode=%d, dma_type=%d, dma_pos=%u, dma_len=%u, cdadr=%04X\n", dma_mode, dma_type, dma_pos, dma_len, uDmaAddr));
3848
3849 /* Skip any accesses below local memory start. */
3850 if ((0x2000 > 0) && (uDmaAddr < 0x2000)) /// @todo Should keep track in variables
3851 {
3852 uint16_t cbToSkip = 0x2000 - uDmaAddr;
3853
3854 uDmaAddr += cbToSkip;
3855 /// @todo Should this write junk to host memory when reading from device?
3856 if (cbToSkip < cbToXfer)
3857 {
3858 cbToXfer -= cbToSkip;
3859 Assert(uDmaAddr == 0x2000);
3860 LogFunc(("DMA skipping %u bytes!\n", cbToSkip));
3861 }
3862 else
3863 {
3864 cbToXfer = 0; /* Transfer entirely below valid address range. */
3865 LogFunc(("DMA below valid address range!\n"));
3866 }
3867 }
3868
3869 if (cbToXfer)
3870 {
3871 uint16_t cbToSkip = 0;
3872
3873 /* Clip transfer size so it falls within local RAM. */
3874 if ((uDmaAddr - 0x2000 + cbToXfer) > (int)sizeof(pThis->abLocalRAM))
3875 {
3876 /* Calculate how much to skip anything at the end. */
3877 cbToSkip = sizeof(pThis->abLocalRAM) - (0x2000 - uDmaAddr + cbToXfer);
3878 LogFunc(("DMA above valid address range uDmaAddr=%04X cbToXfer=%u cbToSkip=%u!\n", uDmaAddr, cbToXfer, cbToSkip));
3879 cbToXfer -= cbToSkip;
3880 }
3881
3882 if (dma_type == DTYPE_WRITE)
3883 {
3884 /* Write transfer type. Reading from device, writing to memory. */
3885 if (!pThis->ga.gacr.ddir)
3886 {
3887 Log2Func(("DMAWriteMemory uDmaAddr=%04X cbToXfer=%u\n", uDmaAddr, cbToXfer));
3888 rc = PDMDevHlpDMAWriteMemory(pDevIns, nchan,
3889 &pThis->abLocalRAM[uDmaAddr - 0x2000],
3890 dma_pos, cbToXfer, &cbXferred);
3891 AssertMsgRC(rc, ("DMAWriteMemory -> %Rrc\n", rc));
3892 }
3893 else
3894 {
3895 // Do nothing, direction does not match.
3896 /// @todo Bug in DevDMA?
3897 LogFunc(("DTYPE_WRITE but GACR.ddir set, do nothing!\n"));
3898 }
3899 }
3900 else
3901 {
3902 /* Read of Verify transfer type. Reading from memory, writing to device. */
3903 if (pThis->ga.gacr.ddir)
3904 {
3905 Log2Func(("DMAReadMemory uDmaAddr=%04X cbToXfer=%u\n", uDmaAddr, cbToXfer));
3906 rc = PDMDevHlpDMAReadMemory(pDevIns, nchan,
3907 &pThis->abLocalRAM[uDmaAddr - 0x2000],
3908 dma_pos, cbToXfer, &cbXferred);
3909 AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
3910 }
3911 else
3912 {
3913 // Do nothing, direction does not match.
3914 /// @todo Bug in DevDMA?
3915 LogFunc(("DTYPE_READ but GACR.ddir clear, do nothing!\n"));
3916 }
3917 }
3918
3919 /* NB: This might wrap. In theory it might wrap back to valid
3920 * memory but... just no.
3921 */
3922 /// @todo Actually... what would really happen?
3923 uDmaAddr += cbToXfer + cbToSkip;
3924 }
3925 Log2Func(("After DMA transfer: uDmaAddr=%04X, cbXferred=%u\n", uDmaAddr, cbXferred));
3926
3927 /* Advance the DMA address and see if transfer completed (it almost certainly did). */
3928 if (1)
3929 {
3930 Log2Func(("DMA completed\n"));
3931 PDMDevHlpDMASetDREQ(pDevIns, pThis->uIsaDma, 0);
3932 pThis->ga.streg.dtc = 1;
3933 pThis->ga.fGaIrq = true;
3934 dp8390CoreUpdateIrq(pDevIns, pThis);
3935 }
3936 else
3937 {
3938 LogFunc(("DMA continuing: uDmaAddr=%04X, cbXferred=%u\n", uDmaAddr, cbXferred));
3939 PDMDevHlpDMASchedule(pDevIns);
3940 }
3941
3942 /* Returns the updated transfer count. */
3943 return dma_pos + dma_len;
3944}
3945
3946
3947/* -=-=-=-=-=- Timer Callbacks -=-=-=-=-=- */
3948
3949/**
3950 * @callback_method_impl{FNTMTIMERDEV, Restore timer callback}
3951 *
3952 * This is only called when we restore a saved state and temporarily
3953 * disconnected the network link to inform the guest that network connections
3954 * should be considered lost.
3955 */
3956static DECLCALLBACK(void) dpNicR3TimerRestore(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)
3957{
3958 RT_NOREF(pvUser);
3959 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
3960 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
3961 AssertReleaseRC(rc);
3962
3963 rc = VERR_GENERAL_FAILURE;
3964
3965 /* The DP8390 based cards have no concept of link state. Reporting collisions on all transmits
3966 * is the best approximation of a disconnected cable that we can do. Some drivers (3C503) warn
3967 * of possible disconnected cable, some don't. Many cards with DP8390 chips had permanently
3968 * attached cables (AUI or BNC) and their drivers do not expect cables to be disconnected and
3969 * re-connected at runtime. Guests which are waiting for a receive have no way to notice any
3970 * problem, therefore we only postpone restoring a link a couple of times, and then reconnect
3971 * regardless of whether the guest noticed anything or not.
3972 */
3973 if ( (pThis->cLinkDownReported <= DPNIC_MAX_LINKDOWN_REPORTED)
3974 && (pThis->cLinkRestorePostponed <= DPNIC_MAX_LINKRST_POSTPONED))
3975 rc = PDMDevHlpTimerSetMillies(pDevIns, hTimer, 1500);
3976 if (RT_FAILURE(rc))
3977 {
3978 pThis->fLinkTempDown = false;
3979 if (pThis->fLinkUp)
3980 {
3981 LogRel(("DPNIC#%d: The link is back up again after the restore.\n",
3982 pThis->iInstance));
3983 LogFunc(("#%d: cLinkDownReported=%d\n", pThis->iInstance, pThis->cLinkDownReported));
3984 pThis->Led.Actual.s.fError = 0;
3985 }
3986 }
3987 else
3988 {
3989 LogFunc(("#%d: cLinkDownReported=%d, cLinkRestorePostponed=%d, wait another 1500ms...\n",
3990 pThis->iInstance, pThis->cLinkDownReported, pThis->cLinkRestorePostponed));
3991 pThis->cLinkRestorePostponed++;
3992 }
3993
3994 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
3995}
3996
3997
3998/* -=-=-=-=-=- Debug Info Handler -=-=-=-=-=- */
3999
4000/**
4001 * @callback_method_impl{FNDBGFHANDLERDEV}
4002 */
4003static DECLCALLBACK(void) dpNicR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
4004{
4005 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4006 bool fRecvBuffer = false;
4007 bool fSendBuffer = false;
4008 unsigned uFreePages;
4009 DP8390CORE *pCore = &pThis->core;
4010 const char *aszModels[] = {"NE1000", "NE2000", "WD8003E", "WD8013E", "3C503"};
4011
4012 /*
4013 * Parse args.
4014 */
4015 if (pszArgs)
4016 {
4017 fRecvBuffer = strstr(pszArgs, "verbose") || strstr(pszArgs, "recvbuf");
4018 fSendBuffer = strstr(pszArgs, "verbose") || strstr(pszArgs, "sendbuf");
4019 }
4020
4021 /*
4022 * Show device information.
4023 */
4024 pHlp->pfnPrintf(pHlp, "DPNIC #%d: %s port=%RTiop IRQ=%u",
4025 pThis->iInstance,
4026 aszModels[pThis->uDevType],
4027 pThis->IOPortBase,
4028 pThis->uIsaIrq);
4029 if (pThis->MemBase)
4030 pHlp->pfnPrintf(pHlp, " mem=%05X-%05X", pThis->MemBase, pThis->MemBase + pThis->cbMemSize - 1);
4031 if (pThis->uIsaDma)
4032 pHlp->pfnPrintf(pHlp, " DMA=%u", pThis->uIsaDma);
4033 pHlp->pfnPrintf(pHlp, " mac-cfg=%RTmac%s %s\n",
4034 &pThis->MacConfigured,
4035 pDevIns->fR0Enabled ? " RZ" : "",
4036 pThis->fDriverAttached ? "attached" : "unattached!");
4037
4038 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_INTERNAL_ERROR); /* Take it here so we know why we're hanging... */
4039 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
4040
4041 pHlp->pfnPrintf(pHlp, "\nDP3890 NIC Core\n");
4042 pHlp->pfnPrintf(pHlp, " CR=%02X: %s%s%s RD=%d PS=%d\n", pCore->CR,
4043 pCore->cr.STP ? "STP " : "",
4044 pCore->cr.STA ? "STA " : "",
4045 pCore->cr.TXP ? "TXP " : "",
4046 pCore->cr.RD, pCore->cr.PS);
4047 pHlp->pfnPrintf(pHlp, " ISR=%02X: %s%s%s%s%s%s%s%s\n", pCore->ISR,
4048 pCore->isr.PRX ? "PRX " : "",
4049 pCore->isr.PTX ? "PTX " : "",
4050 pCore->isr.RXE ? "RXE " : "",
4051 pCore->isr.TXE ? "TXE " : "",
4052 pCore->isr.OVW ? "OVW " : "",
4053 pCore->isr.CNT ? "CNT " : "",
4054 pCore->isr.RDC ? "RDC " : "",
4055 pCore->isr.RST ? "RST " : "");
4056 pHlp->pfnPrintf(pHlp, " IMR=%02X: %s%s%s%s%s%s%s%s\n", pCore->IMR,
4057 pCore->imr.PRXE ? "PRXE " : "",
4058 pCore->imr.PTXE ? "PTXE " : "",
4059 pCore->imr.RXEE ? "RXEE " : "",
4060 pCore->imr.TXEE ? "TXEE " : "",
4061 pCore->imr.OVWE ? "OVWE " : "",
4062 pCore->imr.CNTE ? "CNTE " : "",
4063 pCore->imr.RDCE ? "RDCE " : "",
4064 pCore->imr.res ? "Reserved bit set!!" : "");
4065 pHlp->pfnPrintf(pHlp, " DCR=%02X: %s%s%s%s%sFT=%d %s\n", pCore->DCR,
4066 pCore->dcr.WTS ? "WTS " : "",
4067 pCore->dcr.BOS ? "BOS " : "",
4068 pCore->dcr.LAS ? "LAS " : "",
4069 pCore->dcr.LS ? "LS " : "",
4070 pCore->dcr.ARM ? "ARM " : "",
4071 pCore->dcr.FT,
4072 pCore->dcr.res ? "Reserved bit set!!" : "");
4073 pHlp->pfnPrintf(pHlp, " TCR=%02X: %sLB=%d %s%s\n", pCore->TCR,
4074 pCore->tcr.CRC ? "CRC " : "",
4075 pCore->tcr.LB,
4076 pCore->tcr.ATD ? "ATD " : "",
4077 pCore->tcr.OFST ? "OFST" : "");
4078 pHlp->pfnPrintf(pHlp, " TSR=%02X: %s%s%s%s%s%s%s%s\n", pCore->TSR,
4079 pCore->tsr.PTX ? "PTX " : "",
4080 pCore->tsr.DFR ? "DFR " : "",
4081 pCore->tsr.COL ? "COL " : "",
4082 pCore->tsr.ABT ? "ABT " : "",
4083 pCore->tsr.CRS ? "CRS " : "",
4084 pCore->tsr.FU ? "FU " : "",
4085 pCore->tsr.CDH ? "CDH " : "",
4086 pCore->tsr.OWC ? "OWC " : "");
4087 pHlp->pfnPrintf(pHlp, " RCR=%02X: %s%s%s%s%s%s\n", pCore->RCR,
4088 pCore->rcr.SEP ? "SEP " : "",
4089 pCore->rcr.AR ? "AR " : "",
4090 pCore->rcr.AB ? "AB " : "",
4091 pCore->rcr.AM ? "AM " : "",
4092 pCore->rcr.PRO ? "PRO " : "",
4093 pCore->rcr.MON ? "MON " : "");
4094 pHlp->pfnPrintf(pHlp, " RSR=%02X: %s%s%s%s%s%s%s%s\n", pCore->RSR,
4095 pCore->rsr.PRX ? "PRX " : "",
4096 pCore->rsr.CRC ? "CRC " : "",
4097 pCore->rsr.FAE ? "FAE " : "",
4098 pCore->rsr.FO ? "FO " : "",
4099 pCore->rsr.MPA ? "MPA " : "",
4100 pCore->rsr.PHY ? "PHY " : "",
4101 pCore->rsr.DIS ? "DIS " : "",
4102 pCore->rsr.DFR ? "DFR " : "");
4103 pHlp->pfnPrintf(pHlp, " ActIntSrc: %02X\n", pCore->ISR & pCore->IMR);
4104 pHlp->pfnPrintf(pHlp, " Receiving: %s%s%s%s%s%s\n",
4105 pCore->rcr.AB ? "Broadcast " : "",
4106 pCore->rcr.AM ? "Multicast " : "",
4107 pCore->rcr.PRO ? "Promiscuous " : "",
4108 pCore->rcr.MON ? "Monitor " : "",
4109 pCore->cr.STA ? "Started " : "Not started ",
4110 pCore->isr.RST ? "Reset!" : "");
4111
4112 /* Dump the currently programmed station address. */
4113 pHlp->pfnPrintf(pHlp, " MAC Addr : %RTmac\n", &pCore->pg1.PAR);
4114
4115 /* Dump the currently programmed multicast filter. */
4116 pHlp->pfnPrintf(pHlp, " Multicast: %02X:%02X:%02X:%02X %02X:%02X:%02X:%02X\n",
4117 pCore->pg1.MAR[0], pCore->pg1.MAR[1], pCore->pg1.MAR[2], pCore->pg1.MAR[3],
4118 pCore->pg1.MAR[4], pCore->pg1.MAR[5], pCore->pg1.MAR[6], pCore->pg1.MAR[7]);
4119
4120 /* Dump the DMA state. */
4121 pHlp->pfnPrintf(pHlp, " Local DMA : TPSR=%02X00 TBCR=%04X CLDA=%04X\n",
4122 pCore->TPSR, pCore->TBCR, pCore->CLDA);
4123 pHlp->pfnPrintf(pHlp, " : PSTART=%02X00 PSTOP=%02X00 CURR=%02X00 BNRY=%02X00\n",
4124 pCore->PSTART, pCore->PSTOP, pCore->CURR, pCore->BNRY);
4125 pHlp->pfnPrintf(pHlp, " Remote DMA: RSAR=%04X RBCR=%04X CRDA=%04X\n",
4126 pCore->RSAR, pCore->RBCR, pCore->CRDA);
4127
4128 /* Try to figure out how much available space there is in the receive ring. */
4129 if (pCore->BNRY <= pCore->CURR)
4130 uFreePages = pCore->PSTOP - pCore->PSTART - (pCore->CURR - pCore->BNRY);
4131 else
4132 uFreePages = pCore->BNRY - pCore->CURR;
4133 pHlp->pfnPrintf(pHlp, " Estimated %u free pages (%u bytes) in receive ring\n", uFreePages, uFreePages * 256);
4134
4135 if (pThis->fMaybeOutOfSpace)
4136 pHlp->pfnPrintf(pHlp, " Waiting for receive space\n");
4137 if (pThis->fLinkTempDown)
4138 {
4139 pHlp->pfnPrintf(pHlp, " Link down count %d\n", pThis->cLinkDownReported);
4140 pHlp->pfnPrintf(pHlp, " Postpone count %d\n", pThis->cLinkRestorePostponed);
4141 }
4142
4143 if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
4144 {
4145 /* Dump the WD specific registers. */
4146 pHlp->pfnPrintf(pHlp, "\nWD80x3 Control Registers\n");
4147 pHlp->pfnPrintf(pHlp, " CTRL1=%02X: %s%s A18-A13=%02X\n", pThis->CTRL1,
4148 pThis->ctrl1.RESET ? "RESET " : "",
4149 pThis->ctrl1.MEME ? "MEME " : "",
4150 pThis->ctrl1.A13_18);
4151 pHlp->pfnPrintf(pHlp, " CTRL2=%02X: %s%s A23-A19=%02X\n", pThis->CTRL2,
4152 pThis->ctrl2.M16 ? "M16 " : "",
4153 pThis->ctrl2.MEMW ? "MEMW " : "",
4154 pThis->ctrl2.A19_23);
4155 }
4156
4157 if (pThis->uDevType == DEV_3C503)
4158 {
4159 PEL_GA pGa = &pThis->ga;
4160
4161 /* Dump the Gate Array state. */
4162 pHlp->pfnPrintf(pHlp, "\n3C503 ASIC Gate Array\n");
4163 pHlp->pfnPrintf(pHlp, " PSTR=%02X00 PSPR=%02X00 cdadr=%04X\n",
4164 pGa->PSTR, pGa->PSTR, pGa->CDADR);
4165 pHlp->pfnPrintf(pHlp, " DQTR=%02X: tb=%d\n", pGa->DQTR,
4166 pGa->dqtr.tb);
4167 pHlp->pfnPrintf(pHlp, " BCFR=%02X PCFR=%02X\n",
4168 pGa->BCFR, pGa->PCFR);
4169 pHlp->pfnPrintf(pHlp, " GACFR=%02X: mbs=%d %s%s%s%s%s\n", pGa->GACFR,
4170 pGa->gacfr.mbs,
4171 pGa->gacfr.rsel ? "rsel " : "",
4172 pGa->gacfr.test ? "test " : "",
4173 pGa->gacfr.ows ? "ows " : "",
4174 pGa->gacfr.tcm ? "tcm " : "",
4175 pGa->gacfr.nim ? "nim " : "");
4176 pHlp->pfnPrintf(pHlp, " GACR=%02X: %s%s%s%s%s%s%s%s\n", pGa->GACR,
4177 pGa->gacr.rst ? "rst " : "",
4178 pGa->gacr.xsel ? "xsel " : "",
4179 pGa->gacr.ealo ? "ealo " : "",
4180 pGa->gacr.eahi ? "eahi " : "",
4181 pGa->gacr.share ? "share " : "",
4182 pGa->gacr.dbsel ? "dbsel " : "",
4183 pGa->gacr.ddir ? "ddir " : "",
4184 pGa->gacr.start ? "start " : "");
4185 pHlp->pfnPrintf(pHlp, " STREG=%02X: rev=%d %s%s%s%s%s\n", pGa->STREG,
4186 pGa->streg.rev,
4187 pGa->streg.dip ? "dip " : "",
4188 pGa->streg.dtc ? "dtc " : "",
4189 pGa->streg.oflw ? "oflw " : "",
4190 pGa->streg.uflw ? "uflw " : "",
4191 pGa->streg.dprdy ? "dprdy " : "");
4192 pHlp->pfnPrintf(pHlp, " IDCFR=%02X: %s%s%s%s%s%s%s\n", pGa->IDCFR,
4193 pGa->idcfr.drq1 ? "drq1 " : "",
4194 pGa->idcfr.drq2 ? "drq2 " : "",
4195 pGa->idcfr.drq3 ? "drq3 " : "",
4196 pGa->idcfr.irq2 ? "irq2 " : "",
4197 pGa->idcfr.irq3 ? "irq3 " : "",
4198 pGa->idcfr.irq4 ? "irq4 " : "",
4199 pGa->idcfr.irq5 ? "irq5 " : "");
4200 pHlp->pfnPrintf(pHlp, " DALSB=%02X DAMSB=%02X addr=%04X\n",
4201 pGa->DALSB, pGa->DAMSB,
4202 RT_MAKE_U16(pGa->DALSB, pGa->DAMSB));
4203 pHlp->pfnPrintf(pHlp, " VPTR0=%02X VPTR1=%02X VPTR2=%02X, VPTR=%X\n",
4204 pGa->VPTR0, pGa->VPTR1, pGa->VPTR2,
4205 (pGa->VPTR2 << 12) | (pGa->VPTR1 << 4) | (pGa->VPTR0 >> 4));
4206
4207
4208
4209 }
4210
4211 /* Dump the beginning of the send buffer. */
4212 if (fSendBuffer)
4213 {
4214 pHlp->pfnPrintf(pHlp, "Send buffer (start at %u):\n", 0);
4215 unsigned dump_end = RT_MIN(0 + 64, sizeof(pThis->abLocalRAM) - 16);
4216 for (unsigned ofs = 0; ofs < dump_end; ofs += 16)
4217 pHlp->pfnPrintf(pHlp, " %04X: %Rhxs\n", ofs, &pThis->abLocalRAM[ofs]);
4218 }
4219
4220 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4221}
4222
4223
4224/* -=-=-=-=-=- Helper(s) -=-=-=-=-=- */
4225
4226
4227static void dpNicR3HardReset(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
4228{
4229 LogFlowFunc(("#%d:\n", pThis->iInstance));
4230
4231 /* Initialize the PROM. Covers both NE1000 and NE2000. */
4232 Assert(sizeof(pThis->MacConfigured) == 6);
4233 memset(pThis->aPROM, 0, sizeof(pThis->aPROM));
4234 /* The first 6 bytes of PROM always contain the configured MAC address. */
4235 memcpy(&pThis->aPROM[0x00], &pThis->MacConfigured, sizeof(pThis->MacConfigured));
4236
4237 if ((pThis->uDevType == DEV_NE1000) || (pThis->uDevType == DEV_NE2000))
4238 {
4239 /* The NE1000/NE2000 repeats the MAC address and also includes BB/WW signature. */
4240 memcpy(&pThis->aPROM[0x10], &pThis->MacConfigured, sizeof(pThis->MacConfigured));
4241 pThis->aPROM[0x0E] = pThis->aPROM[0x0F] = 'W'; /* Word-wide. */
4242 pThis->aPROM[0x1E] = pThis->aPROM[0x1F] = 'B'; /* Byte-wide. */
4243 }
4244 else if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
4245 {
4246 /* The WD8003/WD8013 only uses 8 bytes of the PROM. The 7th byte
4247 * contains a board ID and the last byte is a checksum calculated
4248 * such that a two's complement sum of the 8 bytes equals FFh.
4249 */
4250 int i;
4251 uint8_t sum;
4252
4253 /* The board ID is 2 for 8003S, 3 for 8003E, 4 for 8003WT, 5 for 8013EBT. */
4254 pThis->aPROM[0x06] = 3;
4255 if (pThis->uDevType == DEV_WD8013)
4256 pThis->aPROM[0x06] = 5;
4257
4258 for (i = 0, sum = 0; i < 7; ++i)
4259 sum += pThis->aPROM[i];
4260
4261 pThis->aPROM[0x07] = 0xff - sum;
4262 }
4263 else if (pThis->uDevType == DEV_3C503)
4264 {
4265 const uint16_t el_io_bases[] = { 0x2E0, 0x2A0, 0x280, 0x250, 0x350, 0x330, 0x310, 0x300, 0 };
4266 const uint32_t el_mem_bases[] = { 0xDC000, 0xD8000, 0xCC000, 0xC8000, 0 };
4267 int i;
4268
4269 /* Zap the Gate Array state. */
4270 memset(&pThis->ga, 0, sizeof(pThis->ga));
4271
4272 /* Find the BCFR value. */
4273 for (i = 0; el_io_bases[i]; ++i)
4274 {
4275 if (pThis->IOPortBase == el_io_bases[i])
4276 break;
4277 }
4278 /// @todo Make sure we somehow disallow values that a 3C503 can't do
4279 if (i < 8)
4280 pThis->ga.BCFR = 1 << i;
4281
4282 /* Find the PCFR value. */
4283 for (i = 0; el_mem_bases[i]; ++i)
4284 {
4285 if (pThis->MemBase == el_mem_bases[i])
4286 break;
4287 }
4288 /// @todo Make sure we somehow disallow values that a 3C503 can't do
4289 if (i < 4)
4290 pThis->ga.PCFR = RT_BIT(7) >> i;
4291 }
4292
4293 /* Clear the local RAM. */
4294 memset(pThis->abLocalRAM, 0, sizeof(pThis->abLocalRAM));
4295
4296 /* Wipe out all of the DP8390 core state. */
4297 memset(&pThis->core, 0, sizeof(pThis->core));
4298
4299 dp8390CoreReset(pDevIns, pThis);
4300}
4301
4302/**
4303 * Takes down the link temporarily if it's current status is up.
4304 *
4305 * This is used during restore and when replumbing the network link.
4306 *
4307 * The temporary link outage is supposed to indicate to the OS that all network
4308 * connections have been lost and that it for instance is appropriate to
4309 * renegotiate any DHCP lease.
4310 *
4311 * @param pDevIns The device instance data.
4312 * @param pThis The device state.
4313 */
4314static void dp8390TempLinkDown(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
4315{
4316 if (pThis->fLinkUp)
4317 {
4318 pThis->fLinkTempDown = true;
4319 pThis->cLinkDownReported = 0;
4320 pThis->cLinkRestorePostponed = 0;
4321 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
4322 int rc = PDMDevHlpTimerSetMillies(pDevIns, pThis->hTimerRestore, pThis->cMsLinkUpDelay);
4323 AssertRC(rc);
4324 }
4325}
4326
4327
4328/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
4329
4330/**
4331 * @callback_method_impl{FNSSMDEVLIVEEXEC, Pass 0 only.}
4332 */
4333static DECLCALLBACK(int) dpNicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
4334{
4335 RT_NOREF(uPass);
4336 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4337 pDevIns->pHlpR3->pfnSSMPutMem(pSSM, &pThis->MacConfigured, sizeof(pThis->MacConfigured));
4338 return VINF_SSM_DONT_CALL_AGAIN;
4339}
4340
4341
4342/**
4343 * @callback_method_impl{FNSSMDEVSAVEPREP,
4344 * Serializes the receive thread, it may be working inside the critsect.}
4345 */
4346static DECLCALLBACK(int) dpNicSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4347{
4348 RT_NOREF(pSSM);
4349 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4350
4351 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
4352 AssertRC(rc);
4353 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4354
4355 return VINF_SUCCESS;
4356}
4357
4358
4359/**
4360 * @callback_method_impl{FNSSMDEVSAVEEXEC}
4361 */
4362static DECLCALLBACK(int) dpNicSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4363{
4364 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4365 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4366
4367 /* Start with saving the generic bits. */
4368 pHlp->pfnSSMPutBool(pSSM, pThis->fLinkUp);
4369 pHlp->pfnSSMPutBool(pSSM, pThis->fNicIrqActive);
4370
4371 /* Continue with DP8390 core. */
4372 pHlp->pfnSSMPutU8(pSSM, pThis->core.CR);
4373 pHlp->pfnSSMPutU8(pSSM, pThis->core.DCR);
4374 pHlp->pfnSSMPutU8(pSSM, pThis->core.ISR);
4375 pHlp->pfnSSMPutU8(pSSM, pThis->core.IMR);
4376 pHlp->pfnSSMPutU8(pSSM, pThis->core.RCR);
4377 pHlp->pfnSSMPutU8(pSSM, pThis->core.RSR);
4378 pHlp->pfnSSMPutU8(pSSM, pThis->core.TCR);
4379 pHlp->pfnSSMPutU8(pSSM, pThis->core.TSR);
4380 pHlp->pfnSSMPutU8(pSSM, pThis->core.NCR);
4381 pHlp->pfnSSMPutU8(pSSM, pThis->core.TPSR);
4382 pHlp->pfnSSMPutU16(pSSM, pThis->core.TBCR);
4383 pHlp->pfnSSMPutU16(pSSM, pThis->core.CLDA);
4384 pHlp->pfnSSMPutU8(pSSM, pThis->core.PSTART);
4385 pHlp->pfnSSMPutU8(pSSM, pThis->core.PSTOP);
4386 pHlp->pfnSSMPutU8(pSSM, pThis->core.CURR);
4387 pHlp->pfnSSMPutU8(pSSM, pThis->core.BNRY);
4388 pHlp->pfnSSMPutU16(pSSM, pThis->core.RSAR);
4389 pHlp->pfnSSMPutU16(pSSM, pThis->core.RBCR);
4390 pHlp->pfnSSMPutU16(pSSM, pThis->core.CRDA);
4391 pHlp->pfnSSMPutU8(pSSM, pThis->core.lnxtpp);
4392 pHlp->pfnSSMPutU8(pSSM, pThis->core.rnxtpp);
4393 pHlp->pfnSSMPutU8(pSSM, pThis->core.CNTR0);
4394 pHlp->pfnSSMPutU8(pSSM, pThis->core.CNTR1);
4395 pHlp->pfnSSMPutU8(pSSM, pThis->core.CNTR2);
4396 pHlp->pfnSSMPutMem(pSSM, &pThis->core.pg1.PAR, sizeof(pThis->core.pg1.PAR));
4397 pHlp->pfnSSMPutMem(pSSM, &pThis->core.pg1.MAR, sizeof(pThis->core.pg1.MAR));
4398 pHlp->pfnSSMPutU8(pSSM, pThis->core.fifo.rp);
4399 pHlp->pfnSSMPutU8(pSSM, pThis->core.fifo.wp);
4400 pHlp->pfnSSMPutMem(pSSM, &pThis->core.fifo.fifo, sizeof(pThis->core.fifo.fifo));
4401
4402 /* Now the WD80x3 state. */
4403 pHlp->pfnSSMPutU8(pSSM, pThis->CTRL1);
4404 pHlp->pfnSSMPutU8(pSSM, pThis->CTRL2);
4405
4406 /* Finally the 3C503-specific state. */
4407 pHlp->pfnSSMPutU8(pSSM, pThis->ga.PSTR);
4408 pHlp->pfnSSMPutU8(pSSM, pThis->ga.PSPR);
4409 pHlp->pfnSSMPutU8(pSSM, pThis->ga.DQTR);
4410 pHlp->pfnSSMPutU8(pSSM, pThis->ga.BCFR);
4411 pHlp->pfnSSMPutU8(pSSM, pThis->ga.PCFR);
4412 pHlp->pfnSSMPutU8(pSSM, pThis->ga.GACFR);
4413 pHlp->pfnSSMPutU8(pSSM, pThis->ga.GACR);
4414 pHlp->pfnSSMPutU8(pSSM, pThis->ga.STREG);
4415 pHlp->pfnSSMPutU8(pSSM, pThis->ga.IDCFR);
4416 pHlp->pfnSSMPutU8(pSSM, pThis->ga.DAMSB);
4417 pHlp->pfnSSMPutU8(pSSM, pThis->ga.DALSB);
4418 pHlp->pfnSSMPutU8(pSSM, pThis->ga.VPTR2);
4419 pHlp->pfnSSMPutU8(pSSM, pThis->ga.VPTR1);
4420 pHlp->pfnSSMPutU8(pSSM, pThis->ga.VPTR0);
4421 pHlp->pfnSSMPutU16(pSSM, pThis->ga.CDADR);
4422 pHlp->pfnSSMPutBool(pSSM, pThis->ga.fGaIrq);
4423
4424 /* Save the configured MAC address. */
4425 pHlp->pfnSSMPutMem(pSSM, &pThis->MacConfigured, sizeof(pThis->MacConfigured));
4426
4427 return VINF_SUCCESS;
4428}
4429
4430
4431/**
4432 * @callback_method_impl{FNSSMDEVLOADPREP},
4433 * Serializes the receive thread, it may be working inside the critsect.}
4434 */
4435static DECLCALLBACK(int) dpNicLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
4436{
4437 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4438 RT_NOREF(pSSM);
4439
4440 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
4441 AssertRC(rc);
4442
4443 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4444
4445 return rc;
4446}
4447
4448
4449/**
4450 * @callback_method_impl{FNSSMDEVLOADEXEC}
4451 */
4452static DECLCALLBACK(int) dpNicLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
4453{
4454 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4455 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
4456 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
4457
4458 if (SSM_VERSION_MAJOR_CHANGED(uVersion, DPNIC_SAVEDSTATE_VERSION))
4459 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
4460
4461 if (uPass == SSM_PASS_FINAL)
4462 {
4463 /* Restore data, first the generic bits. */
4464 pHlp->pfnSSMGetBool(pSSM, &pThis->fLinkUp);
4465 pHlp->pfnSSMGetBool(pSSM, &pThis->fNicIrqActive);
4466
4467 /* Now the DP8390 core. */
4468 pHlp->pfnSSMGetU8(pSSM, &pThis->core.CR);
4469 pHlp->pfnSSMGetU8(pSSM, &pThis->core.DCR);
4470 pHlp->pfnSSMGetU8(pSSM, &pThis->core.ISR);
4471 pHlp->pfnSSMGetU8(pSSM, &pThis->core.IMR);
4472 pHlp->pfnSSMGetU8(pSSM, &pThis->core.RCR);
4473 pHlp->pfnSSMGetU8(pSSM, &pThis->core.RSR);
4474 pHlp->pfnSSMGetU8(pSSM, &pThis->core.TCR);
4475 pHlp->pfnSSMGetU8(pSSM, &pThis->core.TSR);
4476 pHlp->pfnSSMGetU8(pSSM, &pThis->core.NCR);
4477 pHlp->pfnSSMGetU8(pSSM, &pThis->core.TPSR);
4478 pHlp->pfnSSMGetU16(pSSM, &pThis->core.TBCR);
4479 pHlp->pfnSSMGetU16(pSSM, &pThis->core.CLDA);
4480 pHlp->pfnSSMGetU8(pSSM, &pThis->core.PSTART);
4481 pHlp->pfnSSMGetU8(pSSM, &pThis->core.PSTOP);
4482 pHlp->pfnSSMGetU8(pSSM, &pThis->core.CURR);
4483 pHlp->pfnSSMGetU8(pSSM, &pThis->core.BNRY);
4484 pHlp->pfnSSMGetU16(pSSM, &pThis->core.RSAR);
4485 pHlp->pfnSSMGetU16(pSSM, &pThis->core.RBCR);
4486 pHlp->pfnSSMGetU16(pSSM, &pThis->core.CRDA);
4487 pHlp->pfnSSMGetU8(pSSM, &pThis->core.lnxtpp);
4488 pHlp->pfnSSMGetU8(pSSM, &pThis->core.rnxtpp);
4489 pHlp->pfnSSMGetU8(pSSM, &pThis->core.CNTR0);
4490 pHlp->pfnSSMGetU8(pSSM, &pThis->core.CNTR1);
4491 pHlp->pfnSSMGetU8(pSSM, &pThis->core.CNTR2);
4492 pHlp->pfnSSMGetMem(pSSM, &pThis->core.pg1.PAR, sizeof(pThis->core.pg1.PAR));
4493 pHlp->pfnSSMGetMem(pSSM, &pThis->core.pg1.MAR, sizeof(pThis->core.pg1.MAR));
4494 pHlp->pfnSSMGetU8(pSSM, &pThis->core.fifo.rp);
4495 pHlp->pfnSSMGetU8(pSSM, &pThis->core.fifo.wp);
4496 pHlp->pfnSSMGetMem(pSSM, &pThis->core.fifo.fifo, sizeof(pThis->core.fifo.fifo));
4497
4498 /* WD80x3-specific state. */
4499 pHlp->pfnSSMGetU8(pSSM, &pThis->CTRL1);
4500 pHlp->pfnSSMGetU8(pSSM, &pThis->CTRL2);
4501
4502 /* 3C503-specific state. */
4503 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.PSTR);
4504 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.PSPR);
4505 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.DQTR);
4506 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.BCFR);
4507 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.PCFR);
4508 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.GACFR);
4509 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.GACR);
4510 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.STREG);
4511 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.IDCFR);
4512 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.DAMSB);
4513 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.DALSB);
4514 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.VPTR2);
4515 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.VPTR1);
4516 pHlp->pfnSSMGetU8(pSSM, &pThis->ga.VPTR0);
4517 pHlp->pfnSSMGetU16(pSSM, &pThis->ga.CDADR);
4518 pHlp->pfnSSMGetBool(pSSM, &pThis->ga.fGaIrq);
4519
4520 /* Set IRQ and DMA based on IDCFR if this is a 3C503. */
4521 if (pThis->uDevType == DEV_3C503)
4522 {
4523 pThis->uIsaIrq = elGetIrqFromIdcfr(pThis->ga.IDCFR);
4524 pThis->uElIsaDma = elGetDrqFromIdcfr(pThis->ga.IDCFR);
4525 }
4526 }
4527
4528 /* check config */
4529 RTMAC Mac;
4530 int rc = pHlp->pfnSSMGetMem(pSSM, &Mac, sizeof(Mac));
4531 AssertRCReturn(rc, rc);
4532 if ( memcmp(&Mac, &pThis->MacConfigured, sizeof(Mac))
4533 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)) )
4534 LogRel(("DPNIC#%u: The mac address differs: config=%RTmac saved=%RTmac\n", pThis->iInstance, &pThis->MacConfigured, &Mac));
4535
4536 if (uPass == SSM_PASS_FINAL)
4537 {
4538 /* update promiscuous mode. */
4539 if (pThisCC->pDrv)
4540 pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, 0 /* promiscuous enabled */);
4541
4542 /* Indicate link down to the guest OS that all network connections have
4543 been lost, unless we've been teleported here. */
4544 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
4545 dp8390TempLinkDown(pDevIns, pThis);
4546 }
4547
4548 return VINF_SUCCESS;
4549}
4550
4551
4552/* -=-=-=-=-=- DPNICSTATE::INetworkDown -=-=-=-=-=- */
4553
4554/**
4555 * Check if the device/driver can receive data now.
4556 *
4557 * Worker for dpNicNet_WaitReceiveAvail(). This must be called before
4558 * the pfnRecieve() method is called.
4559 *
4560 * @returns VBox status code.
4561 * @param pDevIns The device instance.
4562 * @param pThis The device instance data.
4563 */
4564static int dp8390CanReceive(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
4565{
4566 DP8390CORE *pCore = &pThis->core;
4567 int rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
4568 AssertReleaseRC(rc);
4569
4570 rc = VINF_SUCCESS;
4571
4572 /*
4573 * The card has typically room for several full-size Ethernet frames but
4574 * the buffers can overflow. We cheat a bit and try to hold off when it
4575 * looks like there is temporarily not enough buffer spave.
4576 *
4577 * If the receiver is disabled, accept packets and drop them to avoid
4578 * pile-ups. If the receiver is enabled, take a closer look.
4579 */
4580 if (pCore->cr.STA && !pCore->cr.STP)
4581 {
4582 /* Receiver is enabled. Find out if we're low on buffer space.
4583 * But if the receive buffer isn't at least 4K big (16 pages),
4584 * don't bother. Typically there will be 5K or more in the
4585 * receive buffer.
4586 */
4587 if (pCore->PSTART + 16 <= pCore->PSTOP)
4588 {
4589 uint16_t free_pages;
4590
4591 /* Free space is between BNRY (host's read pointer) and CURR
4592 * (NIC's write pointer).
4593 */
4594 if (pCore->BNRY <= pCore->CURR)
4595 {
4596 /* Free space wraps around. This might technically give
4597 * the wrong answer if the buffer is empty (BNRY = CURR)
4598 * but in that case there's plenty of room anyway.
4599 */
4600 free_pages = pCore->PSTOP - pCore->PSTART - (pCore->CURR - pCore->BNRY);
4601 }
4602 else
4603 {
4604 /* Free space does not wrap. */
4605 free_pages = pCore->BNRY - pCore->CURR;
4606 }
4607 Log2Func(("#%d: %u free pages (%u bytes)\n", pThis->iInstance, free_pages, free_pages * 256));
4608
4609 /* Six pages (1,536 bytes) is enough for the longest standard Ethernet frame
4610 * (1522 bytes including FCS) plus packet header (4 bytes).
4611 */
4612 if (free_pages < 6)
4613 {
4614 rc = VERR_NET_NO_BUFFER_SPACE;
4615 Log2Func(("#%d: Buffer space low, returning %Rrc!\n", pThis->iInstance, rc));
4616 }
4617 }
4618 }
4619
4620 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4621 return rc;
4622}
4623
4624
4625/**
4626 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
4627 */
4628static DECLCALLBACK(int) dpNicNet_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
4629{
4630 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, INetworkDown);
4631 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4632 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4633
4634 int rc = dp8390CanReceive(pDevIns, pThis);
4635 if (RT_SUCCESS(rc))
4636 {
4637 STAM_COUNTER_INC(&pThis->StatRxCanReceiveNow);
4638 return VINF_SUCCESS;
4639 }
4640 if (RT_UNLIKELY(cMillies == 0))
4641 {
4642 STAM_COUNTER_INC(&pThis->StatRxCannotReceiveNow);
4643 return VINF_SUCCESS; //VERR_NET_NO_BUFFER_SPACE;
4644 }
4645
4646 rc = VERR_INTERRUPTED;
4647 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true);
4648 STAM_PROFILE_START(&pThis->StatRxOverflow, a);
4649 VMSTATE enmVMState;
4650 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pDevIns)) == VMSTATE_RUNNING
4651 || enmVMState == VMSTATE_RUNNING_LS))
4652 {
4653 int rc2 = dp8390CanReceive(pDevIns, pThis);
4654 if (RT_SUCCESS(rc2))
4655 {
4656 rc = VINF_SUCCESS;
4657 break;
4658 }
4659 if (cMillies > 666)
4660 cMillies = 666;
4661 LogFlowFunc(("Waiting cMillies=%u...\n", cMillies));
4662
4663 rc2 = RTSemEventWait(pThis->hEventOutOfRxSpace, cMillies);
4664//LogRelFunc(("RTSemEventWait: rc=%Rrc\n", rc2));
4665// if (rc2 == VERR_TIMEOUT)
4666// break;
4667 }
4668 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a);
4669 ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false);
4670
4671 return rc;
4672}
4673
4674
4675/**
4676 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
4677 */
4678static DECLCALLBACK(int) dpNicNet_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
4679{
4680 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, INetworkDown);
4681 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4682 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4683 int rc;
4684
4685 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
4686 rc = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
4687 AssertReleaseRC(rc);
4688
4689 if (cb > 50) /* unqualified guess */
4690 pThis->Led.Asserted.s.fReading = pThis->Led.Actual.s.fReading = 1;
4691 dp8390CoreReceiveLocked(pDevIns, pThis, (const uint8_t *)pvBuf, cb);
4692 pThis->Led.Actual.s.fReading = 0;
4693
4694 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4695 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
4696
4697 return VINF_SUCCESS;
4698}
4699
4700
4701/**
4702 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
4703 */
4704static DECLCALLBACK(void) dpNicNet_XmitPending(PPDMINETWORKDOWN pInterface)
4705{
4706 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, INetworkDown);
4707 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4708 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4709 dp8390CoreXmitPacket(pDevIns, pThis, true /*fOnWorkerThread*/);
4710}
4711
4712
4713/* -=-=-=-=-=- DPNICSTATE::INetworkConfig -=-=-=-=-=- */
4714
4715/**
4716 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetMac}
4717 */
4718static DECLCALLBACK(int) dpNicGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
4719{
4720 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, INetworkConfig);
4721 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4722 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4723
4724 LogFlowFunc(("#%d\n", pThis->iInstance));
4725 /// @todo This is broken!! We can't properly get the MAC address set by the guest
4726#if 0
4727 memcpy(pMac, pThis->core.pg1.PAR, sizeof(*pMac));
4728#else
4729 memcpy(pMac, pThis->aPROM, sizeof(*pMac));
4730#endif
4731 return VINF_SUCCESS;
4732}
4733
4734
4735/**
4736 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
4737 */
4738static DECLCALLBACK(PDMNETWORKLINKSTATE) dpNicGetLinkState(PPDMINETWORKCONFIG pInterface)
4739{
4740 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, INetworkConfig);
4741 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4742 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4743
4744 if (pThis->fLinkUp && !pThis->fLinkTempDown)
4745 return PDMNETWORKLINKSTATE_UP;
4746 if (!pThis->fLinkUp)
4747 return PDMNETWORKLINKSTATE_DOWN;
4748 if (pThis->fLinkTempDown)
4749 return PDMNETWORKLINKSTATE_DOWN_RESUME;
4750 AssertMsgFailed(("Invalid link state!\n"));
4751 return PDMNETWORKLINKSTATE_INVALID;
4752}
4753
4754
4755/**
4756 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState}
4757 */
4758static DECLCALLBACK(int) dpNicSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
4759{
4760 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, INetworkConfig);
4761 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4762 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4763 bool fLinkUp;
4764
4765 LogFlowFunc(("#%d\n", pThis->iInstance));
4766 AssertMsgReturn(enmState > PDMNETWORKLINKSTATE_INVALID && enmState <= PDMNETWORKLINKSTATE_DOWN_RESUME,
4767 ("Invalid link state: enmState=%d\n", enmState), VERR_INVALID_PARAMETER);
4768
4769 if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME)
4770 {
4771 dp8390TempLinkDown(pDevIns, pThis);
4772 /*
4773 * Note that we do not notify the driver about the link state change because
4774 * the change is only temporary and can be disregarded from the driver's
4775 * point of view (see @bugref{7057}).
4776 */
4777 return VINF_SUCCESS;
4778 }
4779 /* has the state changed? */
4780 fLinkUp = enmState == PDMNETWORKLINKSTATE_UP;
4781 if (pThis->fLinkUp != fLinkUp)
4782 {
4783 pThis->fLinkUp = fLinkUp;
4784 if (fLinkUp)
4785 {
4786 /* Connect with a configured delay. */
4787 pThis->fLinkTempDown = true;
4788 pThis->cLinkDownReported = 0;
4789 pThis->cLinkRestorePostponed = 0;
4790 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
4791 int rc = PDMDevHlpTimerSetMillies(pDevIns, pThis->hTimerRestore, pThis->cMsLinkUpDelay);
4792 AssertRC(rc);
4793 }
4794 else
4795 {
4796 /* Disconnect. */
4797 pThis->cLinkDownReported = 0;
4798 pThis->cLinkRestorePostponed = 0;
4799 pThis->Led.Asserted.s.fError = pThis->Led.Actual.s.fError = 1;
4800 }
4801 Assert(!PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
4802 if (pThisCC->pDrv)
4803 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState);
4804 }
4805 return VINF_SUCCESS;
4806}
4807
4808
4809/* -=-=-=-=-=- DPNICSTATE::ILeds (LUN#0) -=-=-=-=-=- */
4810
4811/**
4812 * @interface_method_impl{PDMILEDPORTS,pfnQueryStatusLed}
4813 */
4814static DECLCALLBACK(int) dpNicQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
4815{
4816 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, ILeds);
4817 PPDMDEVINS pDevIns = pThisCC->pDevIns;
4818 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4819 if (iLUN == 0)
4820 {
4821 *ppLed = &pThis->Led;
4822 return VINF_SUCCESS;
4823 }
4824 return VERR_PDM_LUN_NOT_FOUND;
4825}
4826
4827
4828/* -=-=-=-=-=- DPNICSTATE::IBase (LUN#0) -=-=-=-=-=- */
4829
4830/**
4831 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4832 */
4833static DECLCALLBACK(void *) dpNicQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
4834{
4835 PDPNICSTATECC pThisCC = RT_FROM_MEMBER(pInterface, DPNICSTATECC, IBase);
4836 Assert(&pThisCC->IBase == pInterface);
4837 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
4838 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThisCC->INetworkDown);
4839 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig);
4840 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThisCC->ILeds);
4841 return NULL;
4842}
4843
4844
4845/* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */
4846
4847/**
4848 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
4849 */
4850static DECLCALLBACK(void) dpNicR3PowerOff(PPDMDEVINS pDevIns)
4851{
4852 /* Poke thread waiting for buffer space. */
4853 dp8390R3WakeupReceive(pDevIns);
4854}
4855
4856
4857/**
4858 * @interface_method_impl{PDMDEVREG,pfnDetach}
4859 *
4860 * One port on the network card has been disconnected from the network.
4861 */
4862static DECLCALLBACK(void) dpNicR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4863{
4864 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4865 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
4866 RT_NOREF(fFlags);
4867 LogFlowFunc(("#%d\n", pThis->iInstance));
4868
4869 AssertLogRelReturnVoid(iLUN == 0);
4870
4871 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
4872 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
4873
4874 /*
4875 * Zero some important members.
4876 */
4877 pThis->fDriverAttached = false;
4878 pThisCC->pDrvBase = NULL;
4879 pThisCC->pDrv = NULL;
4880
4881 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4882}
4883
4884
4885/**
4886 * @interface_method_impl{PDMDEVREG,pfnAttach}
4887 * One port on the network card has been connected to a network.
4888 */
4889static DECLCALLBACK(int) dpNicR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
4890{
4891 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4892 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
4893 RT_NOREF(fFlags);
4894 LogFlowFunc(("#%d\n", pThis->iInstance));
4895
4896 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
4897
4898 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, &pThis->CritSect, VERR_SEM_BUSY);
4899 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, &pThis->CritSect, rcLock);
4900
4901 /*
4902 * Attach the driver.
4903 */
4904 int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "Network Port");
4905 if (RT_SUCCESS(rc))
4906 {
4907 pThisCC->pDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMINETWORKUP);
4908 AssertMsgStmt(pThisCC->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
4909 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
4910 pThis->fDriverAttached = true;
4911 }
4912 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
4913 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
4914 {
4915 /* This should never happen because this function is not called
4916 * if there is no driver to attach! */
4917 LogFunc(("#%d No attached driver!\n", pThis->iInstance));
4918 }
4919
4920 /*
4921 * Temporarily drop the link if it was up so that the guest
4922 * will know that we have changed the configuration of the
4923 * network card
4924 */
4925 if (RT_SUCCESS(rc))
4926 dp8390TempLinkDown(pDevIns, pThis);
4927
4928 PDMDevHlpCritSectLeave(pDevIns, &pThis->CritSect);
4929 return rc;
4930}
4931
4932
4933/**
4934 * @interface_method_impl{PDMDEVREG,pfnSuspend}
4935 */
4936static DECLCALLBACK(void) dpNicR3Suspend(PPDMDEVINS pDevIns)
4937{
4938 /* Poke thread waiting for buffer space. */
4939 dp8390R3WakeupReceive(pDevIns);
4940}
4941
4942
4943/**
4944 * @interface_method_impl{PDMDEVREG,pfnReset}
4945 */
4946static DECLCALLBACK(void) dpNicR3Reset(PPDMDEVINS pDevIns)
4947{
4948 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4949 LogFlowFunc(("#%d\n", pThis->iInstance));
4950 if (pThis->fLinkTempDown)
4951 {
4952 pThis->cLinkDownReported = 0x1000;
4953 pThis->cLinkRestorePostponed = 0x1000;
4954 PDMDevHlpTimerStop(pDevIns, pThis->hTimerRestore);
4955 dpNicR3TimerRestore(pDevIns, pThis->hTimerRestore, pThis);
4956 }
4957
4958 dpNicR3HardReset(pDevIns, pThis);
4959}
4960
4961
4962/**
4963 * @interface_method_impl{PDMDEVREG,pfnRelocate}
4964 */
4965static DECLCALLBACK(void) dpNicR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
4966{
4967 PDPNICSTATERC pThisRC = PDMINS_2_DATA_RC(pDevIns, PDPNICSTATERC);
4968 pThisRC->pDrv += offDelta;
4969}
4970
4971
4972/**
4973 * @interface_method_impl{PDMDEVREG,pfnDestruct}
4974 */
4975static DECLCALLBACK(int) dpNicR3Destruct(PPDMDEVINS pDevIns)
4976{
4977 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
4978 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4979
4980 if (PDMDevHlpCritSectIsInitialized(pDevIns, &pThis->CritSect))
4981 {
4982 RTSemEventSignal(pThis->hEventOutOfRxSpace);
4983 RTSemEventDestroy(pThis->hEventOutOfRxSpace);
4984 pThis->hEventOutOfRxSpace = NIL_RTSEMEVENT;
4985 PDMDevHlpCritSectDelete(pDevIns, &pThis->CritSect);
4986 }
4987 return VINF_SUCCESS;
4988}
4989
4990
4991/**
4992 * @interface_method_impl{PDMDEVREG,pfnConstruct}
4993 */
4994static DECLCALLBACK(int) dpNicR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
4995{
4996 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
4997 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
4998 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
4999 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
5000 PPDMIBASE pBase;
5001 char szTmp[128];
5002 int rc;
5003
5004 /*
5005 * Init what's required to make the destructor safe.
5006 */
5007 pThis->iInstance = iInstance;
5008 pThis->hEventOutOfRxSpace = NIL_RTSEMEVENT;
5009 pThis->hIoPortsNic = NIL_IOMIOPORTHANDLE;
5010 pThis->hIoPortsCore = NIL_IOMIOPORTHANDLE;
5011 pThisCC->pDevIns = pDevIns;
5012
5013 /*
5014 * Validate configuration.
5015 */
5016 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|CableConnected|Port|MemBase|IRQ|DMA|DeviceType|LinkUpDelay|LineSpeed", "");
5017
5018 /*
5019 * Read the configuration.
5020 */
5021 rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", &pThis->MacConfigured, sizeof(pThis->MacConfigured));
5022 if (RT_FAILURE(rc))
5023 return PDMDEV_SET_ERROR(pDevIns, rc,
5024 N_("Configuration error: Failed to get the \"MAC\" value"));
5025 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "CableConnected", &pThis->fLinkUp, true);
5026 if (RT_FAILURE(rc))
5027 return PDMDEV_SET_ERROR(pDevIns, rc,
5028 N_("Configuration error: Failed to get the \"CableConnected\" value"));
5029
5030 /*
5031 * Determine the model.
5032 */
5033 char szDeviceType[16];
5034 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "DeviceType", &szDeviceType[0], sizeof(szDeviceType), "NE2000");
5035 if (RT_FAILURE(rc))
5036 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Querying \"ChipType\" as string failed"));
5037
5038 if (!strcmp(szDeviceType, "NE1000"))
5039 pThis->uDevType = DEV_NE1000; /* Novell NE1000. */
5040 else if (!strcmp(szDeviceType, "NE2000"))
5041 pThis->uDevType = DEV_NE2000; /* Novell NE2000. */
5042 else if (!strcmp(szDeviceType, "WD8003"))
5043 pThis->uDevType = DEV_WD8003; /* WD EtherCard Plus. */
5044 else if (!strcmp(szDeviceType, "WD8013"))
5045 pThis->uDevType = DEV_WD8013; /* WD EtherCard Plus 16. */
5046 else if (!strcmp(szDeviceType, "3C503"))
5047 pThis->uDevType = DEV_3C503; /* 3Com 3C503 EtherLink II. */
5048 else
5049 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
5050 N_("Configuration error: The \"DeviceType\" value \"%s\" is unsupported"),
5051 szDeviceType);
5052
5053
5054 /*
5055 * Default resource assignments depend on the device type.
5056 */
5057 unsigned uDefIoPort = 0; /* To be overridden. */
5058 unsigned uDefIrq = 0;
5059 unsigned uDefDma = 0; /* Default to no DMA. */
5060 unsigned uDefMemBase = 0; /* Default to no shared memory. */
5061
5062 if ((pThis->uDevType == DEV_NE1000) || (pThis->uDevType == DEV_NE2000))
5063 {
5064 uDefIoPort = 0x300;
5065 uDefIrq = 3;
5066 }
5067 else if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
5068 {
5069 uDefIoPort = 0x280;
5070 uDefIrq = 3;
5071 uDefMemBase = 0xd0000;
5072 pThis->cbMemSize = _8K;
5073 if (pThis->uDevType == DEV_WD8013)
5074 pThis->cbMemSize = _16K;
5075 }
5076 else if (pThis->uDevType == DEV_3C503)
5077 {
5078 uDefIoPort = 0x300;
5079 uDefIrq = 3;
5080 uDefDma = 1;
5081 uDefMemBase = 0xdc000;
5082 pThis->cbMemSize = _8K;
5083 }
5084
5085 /*
5086 * Process ISA configuration options.
5087 */
5088 rc = pHlp->pfnCFGMQueryPortDef(pCfg, "Port", &pThis->IOPortBase, uDefIoPort);
5089 if (RT_FAILURE(rc))
5090 return PDMDEV_SET_ERROR(pDevIns, rc,
5091 N_("Configuration error: Failed to get the \"Port\" value"));
5092
5093 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IRQ", &pThis->uIsaIrq, uDefIrq);
5094 if (RT_FAILURE(rc))
5095 return PDMDEV_SET_ERROR(pDevIns, rc,
5096 N_("Configuration error: Failed to get the \"IRQ\" value"));
5097
5098 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "DMA", &pThis->uIsaDma, uDefDma);
5099 if (RT_FAILURE(rc))
5100 return PDMDEV_SET_ERROR(pDevIns, rc,
5101 N_("Configuration error: Failed to get the \"DMA\" value"));
5102
5103 rc = pHlp->pfnCFGMQueryGCPtrDef(pCfg, "MemBase", &pThis->MemBase, uDefMemBase);
5104 if (RT_FAILURE(rc))
5105 return PDMDEV_SET_ERROR(pDevIns, rc,
5106 N_("Configuration error: Failed to get the \"MemBase\" value"));
5107
5108
5109
5110 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "LinkUpDelay", (uint32_t*)&pThis->cMsLinkUpDelay, 5000); /* ms */
5111 if (RT_FAILURE(rc))
5112 return PDMDEV_SET_ERROR(pDevIns, rc,
5113 N_("Configuration error: Failed to get the value of 'LinkUpDelay'"));
5114 Assert(pThis->cMsLinkUpDelay <= 300000); /* less than 5 minutes */
5115 if (pThis->cMsLinkUpDelay > 5000 || pThis->cMsLinkUpDelay < 100)
5116 {
5117 LogRel(("DPNIC#%d WARNING! Link up delay is set to %u seconds!\n",
5118 iInstance, pThis->cMsLinkUpDelay / 1000));
5119 }
5120 LogFunc(("#%d Link up delay is set to %u seconds\n",
5121 iInstance, pThis->cMsLinkUpDelay / 1000));
5122
5123
5124 /*
5125 * Initialize data (most of it anyway).
5126 */
5127 pThis->Led.u32Magic = PDMLED_MAGIC;
5128 /* IBase */
5129 pThisCC->IBase.pfnQueryInterface = dpNicQueryInterface;
5130 /* INetworkPort */
5131 pThisCC->INetworkDown.pfnWaitReceiveAvail = dpNicNet_WaitReceiveAvail;
5132 pThisCC->INetworkDown.pfnReceive = dpNicNet_Receive;
5133 pThisCC->INetworkDown.pfnXmitPending = dpNicNet_XmitPending;
5134 /* INetworkConfig */
5135 pThisCC->INetworkConfig.pfnGetMac = dpNicGetMac;
5136 pThisCC->INetworkConfig.pfnGetLinkState = dpNicGetLinkState;
5137 pThisCC->INetworkConfig.pfnSetLinkState = dpNicSetLinkState;
5138 /* ILeds */
5139 pThisCC->ILeds.pfnQueryStatusLed = dpNicQueryStatusLed;
5140
5141 pThis->hIoPortsCore = NIL_IOMIOPORTHANDLE;
5142 pThis->hIoPortsNic = NIL_IOMIOPORTHANDLE;
5143 pThis->hSharedMem = NIL_IOMMMIOHANDLE;
5144
5145 /*
5146 * We use our own critical section (historical reasons).
5147 */
5148 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "DPNIC#%u", iInstance);
5149 AssertRCReturn(rc, rc);
5150 rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
5151 AssertRCReturn(rc, rc);
5152
5153 rc = RTSemEventCreate(&pThis->hEventOutOfRxSpace);
5154 AssertRCReturn(rc, rc);
5155
5156 /*
5157 * Register ISA I/O ranges. This depends on the device type.
5158 */
5159 if ((pThis->uDevType == DEV_NE1000) || (pThis->uDevType == DEV_NE2000))
5160 {
5161 /* The NE1000 and NE2000 map the DP8390 at the beginning of the port range,
5162 * followed by the data/reset ports.
5163 */
5164 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase, 0x10 /*cPorts*/, dp8390CoreIOPortWrite, dp8390CoreIOPortRead,
5165 "DP8390-Core", NULL /*paExtDesc*/, &pThis->hIoPortsCore);
5166 if (RT_FAILURE(rc))
5167 return rc;
5168 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase + 0x10, 0x10 /*cPorts*/, neIOPortWrite, neIOPortRead,
5169 "DPNIC-NE", NULL /*paExtDesc*/, &pThis->hIoPortsNic);
5170 if (RT_FAILURE(rc))
5171 return rc;
5172 }
5173 else if ((pThis->uDevType == DEV_WD8003) || (pThis->uDevType == DEV_WD8013))
5174 {
5175 /* The WD8003 and WD8013 map the DP8390 at the end of the port range
5176 * (16 bytes into it). The first 8 bytes of the range are largely unused
5177 * while the second 8 bytes map the PROM.
5178 */
5179 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase, 0x10 /*cPorts*/, wdIOPortWrite, wdIOPortRead,
5180 "DPNIC-WD", NULL /*paExtDesc*/, &pThis->hIoPortsNic);
5181 if (RT_FAILURE(rc))
5182 return rc;
5183 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase + 0x10, 0x10 /*cPorts*/, dp8390CoreIOPortWrite, dp8390CoreIOPortRead,
5184 "DP8390-Core", NULL /*paExtDesc*/, &pThis->hIoPortsCore);
5185 if (RT_FAILURE(rc))
5186 return rc;
5187
5188 /*
5189 * Shared memory MMIO area. This is rather lame.
5190 */
5191 rc = PDMDevHlpMmioCreateExAndMap(pDevIns, pThis->MemBase, pThis->cbMemSize,
5192 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU | IOMMMIO_FLAGS_ABS,
5193 NULL /*pPciDev*/, UINT32_MAX /*iPciRegion*/,
5194 wdMemWrite, wdMemRead, NULL /*wdMmioFill*/, NULL /*pvUser*/,
5195 "DPNIC - WD Shared RAM", &pThis->hSharedMem);
5196 AssertRCReturn(rc, rc);
5197
5198 /* Hack to make WD drivers happy. */
5199 memcpy(&pThis->MacConfigured, "\x00\x00\xC0", 3);
5200 }
5201 else if (pThis->uDevType == DEV_3C503)
5202 {
5203 /* The 3C503 maps the DP8390 at the base I/O address, except the first
5204 * or second 16 bytes of PROM can be mapped into the same space. The
5205 * custom Gate Array is mapped at I/O base + 400h.
5206 */
5207 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase, 0x10 /*cPorts*/, dp8390CoreIOPortWrite, dp8390CoreIOPortRead,
5208 "DP8390-Core", NULL /*paExtDesc*/, &pThis->hIoPortsCore);
5209 if (RT_FAILURE(rc))
5210 return rc;
5211
5212 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOPortBase + 0x400, 0x10 /*cPorts*/, elIOPortWrite, elIOPortRead,
5213 "DPNIC-EL", NULL /*paExtDesc*/, &pThis->hIoPortsNic);
5214 if (RT_FAILURE(rc))
5215 return rc;
5216
5217 /*
5218 * Shared memory MMIO area. The same lame thing.
5219 */
5220 rc = PDMDevHlpMmioCreateExAndMap(pDevIns, pThis->MemBase, pThis->cbMemSize,
5221 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU | IOMMMIO_FLAGS_ABS,
5222 NULL /*pPciDev*/, UINT32_MAX /*iPciRegion*/,
5223 elMemWrite, elMemRead, NULL /*elMmioFill*/, NULL /*pvUser*/,
5224 "DPNIC - 3C503 Shared RAM", &pThis->hSharedMem);
5225 AssertRCReturn(rc, rc);
5226
5227 /*
5228 * Register DMA channel.
5229 */
5230 if ((pThis->uIsaDma >= ELNKII_MIN_VALID_DMA) && (pThis->uIsaDma <= ELNKII_MAX_VALID_DMA))
5231 {
5232 rc = PDMDevHlpDMARegister(pDevIns, pThis->uIsaDma, elnk3R3DMAXferHandler, pThis);
5233 if (RT_FAILURE(rc))
5234 return rc;
5235 LogRel(("DPNIC#%d: Enabling 3C503 DMA channel %u\n", iInstance, pThis->uIsaDma));
5236 }
5237 else
5238 LogRel(("DPNIC#%d: Disabling 3C503 DMA\n", iInstance));
5239
5240 /* Hack to make 3C503 diagnostics happy. */
5241 memcpy(&pThis->MacConfigured, "\x02\x60\x8C", 3);
5242 }
5243
5244
5245 rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, dpNicR3TimerRestore, NULL, TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
5246 "DPNIC Link Restore Timer", &pThis->hTimerRestore);
5247 if (RT_FAILURE(rc))
5248 return rc;
5249
5250 rc = PDMDevHlpSSMRegisterEx(pDevIns, DPNIC_SAVEDSTATE_VERSION, sizeof(*pThis), NULL,
5251 NULL, dpNicLiveExec, NULL,
5252 dpNicSavePrep, dpNicSaveExec, NULL,
5253 dpNicLoadPrep, dpNicLoadExec, NULL);
5254 if (RT_FAILURE(rc))
5255 return rc;
5256
5257 /*
5258 * Create the transmit notifier signaller.
5259 */
5260 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "DPNIC-Xmit", dpNicR3XmitTaskCallback, NULL /*pvUser*/, &pThis->hXmitTask);
5261 if (RT_FAILURE(rc))
5262 return rc;
5263
5264 /*
5265 * Create the RX notifier signaller.
5266 */
5267 rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "DPNIC-Rcv", dpNicR3CanRxTaskCallback, NULL /*pvUser*/, &pThis->hCanRxTask);
5268 if (RT_FAILURE(rc))
5269 return rc;
5270
5271 /*
5272 * Register the info item.
5273 */
5274 RTStrPrintf(szTmp, sizeof(szTmp), "dpnic%d", pThis->iInstance);
5275 PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "dpnic info", dpNicR3Info);
5276
5277 /*
5278 * Attach status driver (optional).
5279 */
5280 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThisCC->IBase, &pBase, "Status Port");
5281 if (RT_SUCCESS(rc))
5282 pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
5283 else if ( rc != VERR_PDM_NO_ATTACHED_DRIVER
5284 && rc != VERR_PDM_CFG_MISSING_DRIVER_NAME)
5285 {
5286 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
5287 return rc;
5288 }
5289
5290 /*
5291 * Attach driver.
5292 */
5293 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "Network Port");
5294 if (RT_SUCCESS(rc))
5295 {
5296 pThisCC->pDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMINETWORKUP);
5297 AssertMsgReturn(pThisCC->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
5298 VERR_PDM_MISSING_INTERFACE_BELOW);
5299 pThis->fDriverAttached = true;
5300 }
5301 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
5302 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
5303 {
5304 /* No error! */
5305 LogFunc(("No attached driver!\n"));
5306 }
5307 else
5308 return rc;
5309
5310 /*
5311 * Reset the device state. (Do after attaching.)
5312 */
5313 dpNicR3HardReset(pDevIns, pThis);
5314
5315 /*
5316 * Register statistics counters.
5317 */
5318 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Public/Net/DPNIC%u/BytesReceived", iInstance);
5319 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Public/Net/DPNIC%u/BytesTransmitted", iInstance);
5320
5321 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/DPNIC%d/ReceiveBytes", iInstance);
5322 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/DPNIC%d/TransmitBytes", iInstance);
5323
5324#ifdef VBOX_WITH_STATISTICS
5325 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in RZ", "/Devices/DPNIC%d/IO/ReadRZ", iInstance);
5326 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOReadR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R3", "/Devices/DPNIC%d/IO/ReadR3", iInstance);
5327 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in RZ", "/Devices/DPNIC%d/IO/WriteRZ", iInstance);
5328 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatIOWriteR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R3", "/Devices/DPNIC%d/IO/WriteR3", iInstance);
5329 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/DPNIC%d/Receive", iInstance);
5330 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/DPNIC%d/RxOverflow", iInstance);
5331 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES , "Nr of RX overflow wakeups", "/Devices/DPNIC%d/RxOverflowWakeup", iInstance);
5332 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxCanReceiveNow, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES , "Can receive immediately", "/Devices/DPNIC%d/RxCanReceiveNow", iInstance);
5333 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatRxCannotReceiveNow, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES , "Cannot receive, not waiting", "/Devices/DPNIC%d/RxCannotReceiveNow", iInstance);
5334 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in RZ", "/Devices/DPNIC%d/Transmit/TotalRZ", iInstance);
5335 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in R3", "/Devices/DPNIC%d/Transmit/TotalR3", iInstance);
5336 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSendRZ, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in RZ", "/Devices/DPNIC%d/Transmit/SendRZ", iInstance);
5337 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatTransmitSendR3, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in R3", "/Devices/DPNIC%d/Transmit/SendR3", iInstance);
5338
5339 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatInterrupt, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling interrupt checks", "/Devices/DPNIC%d/UpdateIRQ", iInstance);
5340
5341 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktMonitor, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet, monitor mode", "/Devices/DPNIC%d/DropPktMonitor", iInstance);
5342 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktRcvrDis, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet, receiver not enabled", "/Devices/DPNIC%d/DropPktRcvrDis", iInstance);
5343 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktVeryShort, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet less than 8 bytes long", "/Devices/DPNIC%d/DropPktVeryShort", iInstance);
5344 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktVMNotRunning,STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet, VM not running", "/Devices/DPNIC%d/DropPktVMNotRunning", iInstance);
5345 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktNoLink, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet, no link", "/Devices/DPNIC%d/DropPktNoLink", iInstance);
5346 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktNoMatch, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet, address match reject", "/Devices/DPNIC%d/DropPktNoMatch", iInstance);
5347 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatDropPktNoBuffer, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Dropped packet, DP8390 buffer overflow", "/Devices/DPNIC%d/DropPktNoBuffer", iInstance);
5348#endif /* VBOX_WITH_STATISTICS */
5349
5350 return VINF_SUCCESS;
5351}
5352
5353#else
5354
5355/**
5356 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
5357 */
5358static DECLCALLBACK(int) dpNicRZConstruct(PPDMDEVINS pDevIns)
5359{
5360 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
5361 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
5362
5363 /* Critical section setup: */
5364 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, &pThis->CritSect);
5365 AssertRCReturn(rc, rc);
5366
5367 /* NIC-specific ISA I/O ports: */
5368 if (pThis->hIoPortsNic != NIL_IOMIOPORTHANDLE)
5369 {
5370 switch (pThis->uDevType)
5371 {
5372 case DEV_NE1000:
5373 case DEV_NE2000:
5374 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNic, neIOPortWrite, neIOPortRead, NULL /*pvUser*/);
5375 AssertRCReturn(rc, rc);
5376 break;
5377 case DEV_WD8003:
5378 case DEV_WD8013:
5379 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNic, wdIOPortWrite, wdIOPortRead, NULL /*pvUser*/);
5380 AssertRCReturn(rc, rc);
5381 break;
5382 case DEV_3C503:
5383 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsNic, elIOPortWrite, elIOPortRead, NULL /*pvUser*/);
5384 AssertRCReturn(rc, rc);
5385 break;
5386 default:
5387 /* Must not happen. */
5388 return VERR_INTERNAL_ERROR;
5389 }
5390 }
5391
5392 /* Common DP8390 core I/O ports: */
5393 if (pThis->hIoPortsCore != NIL_IOMIOPORTHANDLE)
5394 {
5395 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsCore, dp8390CoreIOPortWrite, dp8390CoreIOPortRead, NULL /*pvUser*/);
5396 AssertRCReturn(rc, rc);
5397 }
5398
5399 /* Shared RAM, if used: */
5400 if (pThis->hSharedMem != NIL_IOMMMIOHANDLE)
5401 {
5402 AssertRCReturn(rc, rc);
5403 switch (pThis->uDevType)
5404 {
5405 case DEV_WD8003:
5406 case DEV_WD8013:
5407 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hSharedMem, wdMemWrite, wdMemRead, NULL /*pvUser*/);
5408 AssertRCReturn(rc, rc);
5409 break;
5410 case DEV_3C503:
5411 rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hSharedMem, elMemWrite, elMemRead, NULL /*pvUser*/);
5412 AssertRCReturn(rc, rc);
5413 break;
5414 case DEV_NE1000:
5415 case DEV_NE2000:
5416 default:
5417 /* Must not happen. */
5418 return VERR_INTERNAL_ERROR;
5419 }
5420 }
5421
5422 return VINF_SUCCESS;
5423}
5424
5425#endif /* IN_RING3 */
5426
5427/**
5428 * The device registration structure.
5429 */
5430const PDMDEVREG g_DeviceDP8390 =
5431{
5432 /* .u32Version = */ PDM_DEVREG_VERSION,
5433 /* .uReserved0 = */ 0,
5434 /* .szName = */ "dp8390",
5435 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
5436 /* .fClass = */ PDM_DEVREG_CLASS_NETWORK,
5437 /* .cMaxInstances = */ ~0U,
5438 /* .uSharedVersion = */ 42,
5439 /* .cbInstanceShared = */ sizeof(DPNICSTATE),
5440 /* .cbInstanceCC = */ sizeof(DPNICSTATECC),
5441 /* .cbInstanceRC = */ sizeof(DPNICSTATERC),
5442 /* .cMaxPciDevices = */ 0,
5443 /* .cMaxMsixVectors = */ 0,
5444 /* .pszDescription = */ "National Semiconductor DP8390 based adapter.\n",
5445#if defined(IN_RING3)
5446 /* .pszRCMod = */ "VBoxDDRC.rc",
5447 /* .pszR0Mod = */ "VBoxDDR0.r0",
5448 /* .pfnConstruct = */ dpNicR3Construct,
5449 /* .pfnDestruct = */ dpNicR3Destruct,
5450 /* .pfnRelocate = */ dpNicR3Relocate,
5451 /* .pfnMemSetup = */ NULL,
5452 /* .pfnPowerOn = */ NULL,
5453 /* .pfnReset = */ dpNicR3Reset,
5454 /* .pfnSuspend = */ dpNicR3Suspend,
5455 /* .pfnResume = */ NULL,
5456 /* .pfnAttach = */ dpNicR3Attach,
5457 /* .pfnDetach = */ dpNicR3Detach,
5458 /* .pfnQueryInterface = */ NULL,
5459 /* .pfnInitComplete = */ NULL,
5460 /* .pfnPowerOff = */ dpNicR3PowerOff,
5461 /* .pfnSoftReset = */ NULL,
5462 /* .pfnReserved0 = */ NULL,
5463 /* .pfnReserved1 = */ NULL,
5464 /* .pfnReserved2 = */ NULL,
5465 /* .pfnReserved3 = */ NULL,
5466 /* .pfnReserved4 = */ NULL,
5467 /* .pfnReserved5 = */ NULL,
5468 /* .pfnReserved6 = */ NULL,
5469 /* .pfnReserved7 = */ NULL,
5470#elif defined(IN_RING0)
5471 /* .pfnEarlyConstruct = */ NULL,
5472 /* .pfnConstruct = */ dpNicRZConstruct,
5473 /* .pfnDestruct = */ NULL,
5474 /* .pfnFinalDestruct = */ NULL,
5475 /* .pfnRequest = */ NULL,
5476 /* .pfnReserved0 = */ NULL,
5477 /* .pfnReserved1 = */ NULL,
5478 /* .pfnReserved2 = */ NULL,
5479 /* .pfnReserved3 = */ NULL,
5480 /* .pfnReserved4 = */ NULL,
5481 /* .pfnReserved5 = */ NULL,
5482 /* .pfnReserved6 = */ NULL,
5483 /* .pfnReserved7 = */ NULL,
5484#elif defined(IN_RC)
5485 /* .pfnConstruct = */ NULL,
5486 /* .pfnReserved0 = */ NULL,
5487 /* .pfnReserved1 = */ NULL,
5488 /* .pfnReserved2 = */ NULL,
5489 /* .pfnReserved3 = */ NULL,
5490 /* .pfnReserved4 = */ NULL,
5491 /* .pfnReserved5 = */ NULL,
5492 /* .pfnReserved6 = */ NULL,
5493 /* .pfnReserved7 = */ NULL,
5494#else
5495# error "Not in IN_RING3, IN_RING0 or IN_RC!"
5496#endif
5497 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
5498};
5499
5500#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use