VirtualBox

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

Last change on this file since 103068 was 98103, checked in by vboxsync, 20 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
RevLine 
[93560]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/*
[98103]7 * Copyright (C) 2022-2023 Oracle and/or its affiliates.
[93560]8 *
[96407]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
[93560]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
[93675]365/** Maximum number of times we postpone restoring a link that is temporarily down. */
366#define DPNIC_MAX_LINKRST_POSTPONED 3
367
[93560]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;
[93675]901 /** Number of times we've postponed the link restore. */
902 uint16_t cLinkRestorePostponed;
[93560]903
904 /** The "hardware" MAC address. */
905 RTMAC MacConfigured;
906
[93601]907 /** Set if DPNICSTATER3::pDrv is not NULL. */
908 bool fDriverAttached;
[93560]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
[93601]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
[93560]1034#ifndef VBOX_DEVICE_STRUCT_TESTCASE
1035
1036
1037/*********************************************************************************************************************************
1038* Internal Functions *
1039*********************************************************************************************************************************/
1040
[93601]1041static int dp8390CoreAsyncXmitLocked(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PDPNICSTATECC pThisCC, bool fOnWorkerThread);
[93560]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{
[93601]1050 return pThis->fDriverAttached && !pThis->fLinkTempDown && pThis->fLinkUp;
[93560]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 {
[93562]1178 unsigned i;
[93560]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 */
[93601]1235static void dp8390CoreUpdateIrq(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]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
[93601]1258 Log2Func(("#%d set irq fNicIrqActive=%d (fCoreIrqActive=%d, fGaIrq=%d)\n", pThis->iInstance, fNicIrqActive, fCoreIrqActive, pThis->ga.fGaIrq));
[93560]1259
1260 /* The IRQ line typically does not change. */
1261 if (RT_UNLIKELY(fNicIrqActive != pThis->fNicIrqActive))
1262 {
[93601]1263 LogFunc(("#%d IRQ=%d, state=%d\n", pThis->iInstance, pThis->uIsaIrq, fNicIrqActive));
[93560]1264 /// @todo Handle IRQ 2/9 elsewhere
[93601]1265 PDMDevHlpISASetIrq(pDevIns, pThis->uIsaIrq == 2 ? 9 : pThis->uIsaIrq, fNicIrqActive);
[93560]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 */
[93601]1275static void dp8390CoreReset(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]1276{
[93601]1277 LogFlowFunc(("#%d:\n", pThis->iInstance));
[93560]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. */
[93601]1294 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]1295}
1296
1297#ifdef IN_RING3
1298
[93601]1299static DECLCALLBACK(void) dp8390R3WakeupReceive(PPDMDEVINS pDevIns)
[93560]1300{
[93601]1301 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
1302 LogFlowFunc(("#%d\n", pThis->iInstance));
[93560]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);
[93601]1315 dp8390R3WakeupReceive(pDevIns);
[93560]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 {
[93601]1327 LogFunc(("#%d: addr=%04X, cb=%X, cb!!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1343 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1356 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1365 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1379 LogFunc(("#%d: Ignoring read at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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 {
[93601]1397 LogFunc(("#%d: addr=%04X, cb=%X, cb!!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1413 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1426 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1435 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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
[93601]1449 LogFunc(("#%d: Ignoring write at addr=%04X cb=%u!\n", pThis->iInstance, addr, cb));
[93560]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{
[93601]1464 LogFlow(("#%d: Initial CURR=%02X00 CLDA=%04X\n", pThis->iInstance, pThis->core.CURR, pThis->core.CLDA));
[93560]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;
[93601]1475 Log2Func(("#%d: cbLeft=%d CURR=%02X00 CLDA=%04X\n", pThis->iInstance, cbLeft, pThis->core.CURR, pThis->core.CLDA));
[93560]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 {
[93601]1487 Log3Func(("#%d: Round up: CLDA=%04X cbPage=%X\n", pThis->iInstance, pThis->core.CLDA, cbPage));
[93560]1488 pThis->core.CLDA += cbPage;
1489 }
1490 else
1491 pThis->core.CLDA += cbWrite;
1492
[93601]1493 Log3Func(("#%d: Final CURR=%02X00 CLDA=%04X\n", pThis->iInstance, pThis->core.CURR, pThis->core.CLDA));
[93560]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);
[93601]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));
[93560]1506 break;
1507 }
1508 cbLeft -= cbWrite;
1509 }
1510}
1511
1512/**
1513 * Write incoming data into the packet buffer.
1514 */
[93601]1515static void dp8390CoreReceiveLocked(PPDMDEVINS pDevIns, PDPNICSTATE pThis, const uint8_t *src, size_t cbToRecv)
[93560]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
[93601]1559 LogFlowFunc(("#%d: size on wire=%d\n", pThis->iInstance, cbToRecv));
[93560]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;
[93601]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));
[93560]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
[93601]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));
[93560]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));
[93601]1677 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]1678 }
1679 else
1680 {
[93601]1681 Log3Func(("#%d Packet did not pass address filter, size=%d\n", pThis->iInstance, cbToRecv));
[93560]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 *
[93601]1694 * @param pDevIns The device instance data.
1695 * @param pThis The device state data.
[93560]1696 * @param fOnWorkerThread Whether we're on a worker thread or on an EMT.
1697 */
[93601]1698static int dp8390CoreXmitPacket(PPDMDEVINS pDevIns, PDPNICSTATE pThis, bool fOnWorkerThread)
[93560]1699{
[93601]1700 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
[93560]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 */
[93601]1707 PPDMINETWORKUP pDrv = pThisCC->pDrv;
[93560]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 */
[93601]1720 int rc2 = dp8390CoreAsyncXmitLocked(pDevIns, pThis, pThisCC, false /*fOnWorkerThread*/);
[93560]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{
[93601]1745 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
[93560]1746 NOREF(pvUser);
1747
1748 /*
1749 * Transmit if we can.
1750 */
[93601]1751 dp8390CoreXmitPacket(pDevIns, pThis, true /*fOnWorkerThread*/);
[93560]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.
[93601]1762 * @param pThisCC The device state for current context.
[93560]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 */
[93601]1769DECLINLINE(int) dp8390XmitAllocBuf(PDPNICSTATE pThis, PDPNICSTATECC pThisCC, size_t cbMin, bool fLoopback,
[93560]1770 PPDMSCATTERGATHER pSgLoop, PPPDMSCATTERGATHER ppSgBuf)
1771{
1772 int rc;
1773
1774 if (!fLoopback)
1775 {
[93601]1776 PPDMINETWORKUP pDrv = pThisCC->pDrv;
[93560]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.
[93601]1814 * @param pDevIns The device instance.
1815 * @param pThisCC The current context device state.
[93560]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 */
[93601]1821DECLINLINE(int) dp8390CoreXmitSendBuf(PPDMDEVINS pDevIns, PDPNICSTATECC pThisCC, bool fLoopback, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
[93560]1822{
[93601]1823 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
[93560]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
[93601]1832 PPDMINETWORKUP pDrv = pThisCC->pDrv;
[93560]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
[93601]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));
[93560]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));
[93601]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));
[93560]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;
[93601]1953 Log3Func(("#%d: Address NOT matched, ignoring FCS errors.\n", pThis->iInstance));
[93560]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 */
[93601]2008DECLINLINE(void) dp8390CoreXmitRead(PPDMDEVINS pDevIns, const unsigned uLocalAddr, const unsigned cbFrame, PPDMSCATTERGATHER pSgBuf, bool fLoopback)
[93560]2009{
[93601]2010 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
2011 unsigned uOfs = 0;
2012 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
[93560]2013 Assert(pSgBuf->cbAvailable >= cbFrame);
2014
2015 pSgBuf->cbUsed = cbFrame;
2016
[93601]2017 LogFlowFunc(("#%d: uLocalAddr=%04X cbFrame=%d\n", pThis->iInstance, uLocalAddr, cbFrame));
[93560]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?!
[93601]2031 LogFunc(("#%d: uOfs=%u, don't know what to do!!\n", pThis->iInstance, uOfs));
[93560]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?!
[93601]2046 LogFunc(("#%d: uOfs=%u, don't know what to do!!\n", pThis->iInstance, uOfs));
[93560]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?!
[93601]2066 LogFunc(("#%d: uOfs=%u, don't know what to do!!\n", pThis->iInstance, uOfs));
[93560]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 */
[93601]2113static void dp8390CoreStartTransmit(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]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)
[93601]2122 PDPNICSTATECC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDPNICSTATECC);
2123 if (!pThisCC->pDrv)
[93560]2124 {
[93601]2125 int rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hXmitTask);
[93560]2126 AssertRC(rc);
2127 }
2128 else
2129#endif
2130 {
[93601]2131 int rc = dp8390CoreXmitPacket(pDevIns, pThis, false /*fOnWorkerThread*/);
[93560]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 */
[93601]2144static void dp8390CoreKickReceive(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]2145{
2146 if (pThis->fMaybeOutOfSpace)
2147 {
2148 LogFlow(("Poking receive thread.\n"));
2149#ifdef IN_RING3
[93601]2150 dp8390R3WakeupReceive(pDevIns);
[93560]2151#else
[93601]2152 int rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hCanRxTask);
[93560]2153 AssertRC(rc);
2154#endif
2155 }
2156}
2157
2158/**
2159 * Try transmitting a frame.
2160 *
2161 * @threads TX or EMT.
2162 */
[93601]2163static int dp8390CoreAsyncXmitLocked(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PDPNICSTATECC pThisCC, bool fOnWorkerThread)
[93560]2164{
[93601]2165 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
[93560]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 {
[93601]2173 LogFunc(("#%d: Nope, CR.TXP is off (fOnWorkerThread=%RTbool)\n", pThis->iInstance, fOnWorkerThread));
[93560]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);
[93601]2200 LogFunc(("#%d: cb=%d, adr=%04X\n", pThis->iInstance, cb, adr));
[93560]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
[93601]2213 rc = dp8390XmitAllocBuf(pThis, pThisCC, cb, fLoopback, &SgLoop, &pSgBuf);
[93560]2214 if (RT_SUCCESS(rc))
2215 {
[93601]2216 dp8390CoreXmitRead(pDevIns, adr, cb, pSgBuf, fLoopback);
2217 rc = dp8390CoreXmitSendBuf(pDevIns, pThisCC, fLoopback, pSgBuf, fOnWorkerThread);
2218 Log2Func(("#%d: rc=%Rrc\n", pThis->iInstance, rc));
[93560]2219 }
2220 else if (rc == VERR_TRY_AGAIN)
2221 {
2222 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatTransmit), a);
[93601]2223 LogFunc(("#%d: rc=%Rrc\n", pThis->iInstance, rc));
[93560]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 */
[93601]2242 LogRel(("DPNIC#%d: Attempt to transmit illegal giant frame (%u bytes) -> signaling error\n", pThis->iInstance, cb));
[93560]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;
[93601]2257 LogFlowFunc(("#%d: TSR=%02X, ISR=%02X\n", pThis->iInstance, pThis->core.TSR, pThis->core.ISR));
[93560]2258
2259 } while (0); /* No loop, because there isn't ever more than one packet to transmit. */
2260
[93601]2261 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]2262
2263 /* If there's anything waiting, this should be a good time to recheck. */
[93601]2264 dp8390CoreKickReceive(pDevIns, pThis);
[93560]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
[93601]2274static uint32_t dp8390CoreRead(PPDMDEVINS pDevIns, PDPNICSTATE pThis, int ofs)
[93560]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. */
[93601]2315 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]2316 return val;
2317 case DPR_P0_R_CNTR1:
2318 val = pThis->core.CNTR1;
2319 pThis->core.CNTR1 = 0; /* Cleared by reading. */
[93601]2320 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]2321 return val;
2322 case DPR_P0_R_CNTR2:
2323 val = pThis->core.CNTR2;
2324 pThis->core.CNTR2 = 0; /* Cleared by reading. */
[93601]2325 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]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. */
[93565]2374 LogFunc(("Reading page 3 register: ofs=%X!\n", ofs));
[93560]2375 return 0;
2376 }
2377}
2378
2379
[93601]2380static int dp8390CoreWriteCR(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t val)
[93560]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. */
[93601]2412 dp8390CoreKickReceive(pDevIns, pThis);
[93560]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. */
[93601]2424 dp8390CoreKickReceive(pDevIns, pThis);
[93560]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. */
[93601]2430 dp8390CoreStartTransmit(pDevIns, pThis);
[93560]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. */
[93565]2443 LogFunc(("RDMA Abort! RD=%d RSAR=%04X RBCR=%04X CRDA=%04X\n", nCr.RD, pThis->core.RSAR, pThis->core.RBCR, pThis->core.CRDA));
[93560]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
[93565]2455 LogFunc(("RDMA SP: RD=%d RSAR=%04X RBCR=%04X CRDA=%04X\n", nCr.RD, pThis->core.RSAR, pThis->core.RBCR, pThis->core.CRDA));
[93560]2456 }
2457 else
2458 {
2459 /* Starting remote DMA read or write. */
[93565]2460 LogFunc(("RDMA: RD=%d RSAR=%04X RBCR=%04X\n", nCr.RD, pThis->core.RSAR, pThis->core.RBCR));
[93560]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
[93601]2471static int dp8390CoreWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, int ofs, uint32_t val)
[93560]2472{
2473 int rc = VINF_SUCCESS;
2474 bool fUpdateIRQ = false;
2475
[93601]2476 Log2Func(("#%d: page=%d reg=%X val=%02X\n", pThis->iInstance, pThis->core.cr.PS, ofs, val));
[93560]2477
2478 /* Command Register exists in all pages. */
2479 if (ofs == DPR_CR)
2480 {
[93601]2481 rc = dp8390CoreWriteCR(pDevIns, pThis, val);
[93560]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. */
[93601]2499 dp8390CoreKickReceive(pDevIns, pThis);
[93560]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)
[93601]2594 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]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
[93601]2735static int neDataPortWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint16_t val)
[93560]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;
[93601]2769 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]2770 }
2771 }
2772 return VINF_SUCCESS;
2773}
2774
2775
[93601]2776static uint16_t neDataPortRead(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]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;
[93601]2813 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]2814 }
2815 }
2816 return val;
2817}
2818
2819
[93601]2820static int neResetPortWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]2821{
2822 LogFlowFunc(("\n"));
[93601]2823 dp8390CoreReset(pDevIns, pThis);
[93560]2824 return VINF_SUCCESS;
2825}
2826
2827
[93601]2828static int dpNeIoWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr, uint32_t val)
[93560]2829{
2830 int reg = addr & 0x0f;
2831 int rc = VINF_SUCCESS;
2832
[93601]2833 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
[93560]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)
[93601]2842 rc = neResetPortWrite(pDevIns, pThis);
[93560]2843 else
[93601]2844 rc = neDataPortWrite(pDevIns, pThis, val);
[93560]2845
2846 return rc;
2847}
2848
2849
[93601]2850static uint32_t neIoRead(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr)
[93560]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
[93601]2864 val = neDataPortRead(pDevIns, pThis);
[93560]2865
[93601]2866 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
[93560]2867 return val;
2868}
2869
2870
[93601]2871static int wdIoWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr, uint32_t val)
[93560]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
[93601]2884 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
[93560]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 {
[93601]2897 dp8390CoreReset(pDevIns, pThis);
[93560]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
[93601]2975 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
[93560]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
[93601]3026static void elWriteIdcfr(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PEL_GA pGa, uint8_t val)
[93560]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 {
[93601]3037 LogFunc(("#%d Switching IRQ=%d -> IRQ=%d\n", pThis->iInstance, uOldIrq, uNewIrq));
[93560]3038 if (pThis->fNicIrqActive)
3039 {
3040 /* This probably isn't supposed to happen. */
[93601]3041 LogFunc(("#%d Moving active IRQ!\n", pThis->iInstance));
[93560]3042 if (uOldIrq)
[93601]3043 PDMDevHlpISASetIrq(pDevIns, uOldIrq, 0);
[93560]3044 if (uNewIrq)
[93601]3045 PDMDevHlpISASetIrq(pDevIns, uNewIrq, 1);
[93560]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?
[93601]3055 LogFunc(("#%d Switching DRQ=%d -> DRQ=%d\n", pThis->iInstance, uOldDrq, uNewDrq));
[93560]3056 pThis->uElIsaDma = uNewDrq;
3057 }
3058
3059 pGa->IDCFR = val;
3060}
3061
3062
[93601]3063static void elWriteGacfr(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PEL_GA pGa, uint8_t val)
[93560]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 {
[93601]3077 LogFunc(("#%d: Unmasking active IRQ!\n", pThis->iInstance));
3078 PDMDevHlpISASetIrq(pDevIns, pThis->uIsaIrq, 1);
[93560]3079 }
3080 else if (pThis->fNicIrqActive && nGacfr.nim)
3081 {
[93601]3082 LogFunc(("#%d: Masking active IRQ\n", pThis->iInstance));
3083 PDMDevHlpISASetIrq(pDevIns, pThis->uIsaIrq, 0);
[93560]3084 }
3085 }
3086
3087 /// @todo rsel/mbs bit change?
3088 if (nGacfr.rsel != pGa->gacfr.rsel)
3089 {
[93601]3090 LogFunc(("#%d: rsel=%u mbs=%u\n", pThis->iInstance, nGacfr.rsel, nGacfr.mbs));
[93560]3091 }
3092
3093 pGa->GACFR = nGACFR;
3094}
3095
3096
[93601]3097static void elSoftReset(PPDMDEVINS pDevIns, PDPNICSTATE pThis)
[93560]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;
[93601]3105 elWriteGacfr(pDevIns, pThis, pGa, 0);
[93560]3106 pGa->STREG = ELNKII_GA_REV;
3107 pGa->VPTR0 = pGa->VPTR1 = pGa->VPTR2 = 0;
3108 pGa->DALSB = pGa->DAMSB = 0;
[93601]3109 elWriteIdcfr(pDevIns, pThis, pGa, 0);
[93560]3110 pGa->GACR = 0x0B; /* Low bit set = in reset state. */
3111 pGa->fGaIrq = false;
3112
3113 /* Reset the NIC core. */
[93601]3114 dp8390CoreReset(pDevIns, pThis);
[93560]3115}
3116
3117
[93601]3118static int elWriteGacr(PPDMDEVINS pDevIns, PDPNICSTATE pThis, PEL_GA pGa, uint8_t val)
[93560]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)
[93601]3131 elSoftReset(pDevIns, pThis);
[93560]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
[93601]3163 PDMDevHlpDMASetDREQ(pDevIns, pThis->uIsaDma, pGa->streg.dprdy);
[93560]3164 if (pGa->streg.dprdy)
[93601]3165 PDMDevHlpDMASchedule(pDevIns);
3166 LogFunc(("#%d: DREQ for channel %u set to %u\n", pThis->iInstance, pThis->uIsaDma, pGa->streg.dprdy));
[93560]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
[93601]3236static int elGaIoWrite(PPDMDEVINS pDevIns, PDPNICSTATE pThis, uint32_t addr, uint32_t val)
[93560]3237{
3238 int reg = addr & 0xf;
3239 int rc = VINF_SUCCESS;
3240 PEL_GA pGa = &pThis->ga;
3241
[93601]3242 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
[93560]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:
[93601]3256 elWriteGacfr(pDevIns, pThis, pGa, val);
[93560]3257 break;
3258 case GAR_GACR:
[93601]3259 rc = elWriteGacr(pDevIns, pThis, pGa, val);
[93560]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;
[93601]3265 dp8390CoreUpdateIrq(pDevIns, pThis);
[93560]3266 break;
3267 case GAR_IDCFR:
[93601]3268 elWriteIdcfr(pDevIns, pThis, pGa, val);
[93560]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
[93601]3361 Log2Func(("#%d: addr=%#06x val=%#04x\n", pThis->iInstance, addr, val & 0xff));
[93560]3362 return val;
3363}
3364
3365
3366/**
3367 * @callback_method_impl{FNIOMIOPORTIN}
3368 */
[93562]3369static DECLCALLBACK(VBOXSTRICTRC)
3370neIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[93560]3371{
[93601]3372 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
[93560]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:
[93601]3383 *pu32 = neIoRead(pDevIns, pThis, reg);
[93560]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 {
[93601]3389 u8Lo = neIoRead(pDevIns, pThis, reg);
[93560]3390 if (reg < 0xf) // This logic is not entirely accurate (wraparound).
[93601]3391 u8Hi = neIoRead(pDevIns, pThis, reg + 1);
[93560]3392 *pu32 = RT_MAKE_U16(u8Lo, u8Hi);
3393 }
3394 else
[93601]3395 *pu32 = neIoRead(pDevIns, pThis, reg);
[93560]3396 break;
3397 default:
[93601]3398 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
[93560]3399 "neIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3400 Port, cb);
3401 }
3402
[93601]3403 Log2Func(("#%d: NE Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
[93560]3404 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3405 return rc;
3406}
3407
3408
3409/**
3410 * @callback_method_impl{FNIOMIOPORTIN}
3411 */
[93562]3412static DECLCALLBACK(VBOXSTRICTRC)
3413wdIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[93560]3414{
[93601]3415 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
[93560]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:
[93601]3436 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
[93560]3437 "wdIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3438 Port, cb);
3439 }
3440
[93601]3441 Log2Func(("#%d: WD Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
[93560]3442 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3443 return rc;
3444}
3445
3446
3447/**
3448 * @callback_method_impl{FNIOMIOPORTIN}
3449 */
[93562]3450static DECLCALLBACK(VBOXSTRICTRC)
3451elIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[93560]3452{
[93601]3453 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
[93560]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:
[93601]3474 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
[93560]3475 "elIOPortRead: unsupported operation size: offset=%#10x cb=%u\n",
3476 Port, cb);
3477 }
3478
[93601]3479 Log2Func(("#%d: EL Port=%RTiop *pu32=%#RX32 cb=%d rc=%Rrc\n", pThis->iInstance, Port, *pu32, cb, rc));
[93560]3480 STAM_PROFILE_ADV_STOP(&pThis->CTX_SUFF_Z(StatIORead), a);
3481 return rc;
3482}
3483
3484
3485/**
3486 * @callback_method_impl{FNIOMIOPORTIN}
3487 */
[93562]3488static DECLCALLBACK(VBOXSTRICTRC)
3489dp8390CoreIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
[93560]3490{
[93601]3491 PDPNICSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PDPNICSTATE);
[93560]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:
[93601]3502 *pu32 = dp8390CoreRead(pDevIns, pThis, reg);
[93560]3503 break;
3504 case 2:
3505 /* Manually split word access. */
[93601]3506 u8Lo = dp8390CoreRead(pDevIns, pThis, reg + 0);
[93560]3507 /* This logic is not entirely accurate. */
3508 if (reg < 0xf)