diff mbox series

[07/10] dp8393x: Implement TBWC0 and TBWC1 registers to restore buffer state

Message ID c37c8c085be7b484fb68a34f0e39851bdd1e48ca.1576286757.git.fthain@telegraphics.com.au
State New
Headers show
Series Fixes for DP8393X SONIC device emulation | expand

Commit Message

Finn Thain Dec. 14, 2019, 1:25 a.m. UTC
Restore the receive buffer state when the SONIC runs out of receive
descriptors. Otherwise it may write the next packet past the end of the
buffer and corrupt guest memory. This implements behaviour described
in section 3.4.6.2 in the datasheet.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
---
 hw/net/dp8393x.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index 3fdc6cc6f9..5e4494a945 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -39,7 +39,7 @@  static const char* reg_names[] = {
     "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
     "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
     "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
-    "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
+    "RWP", "TRBA0", "TRBA1", "TBWC0", "TBWC1", "0x1d", "0x1e", "LLFA",
     "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
     "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
     "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
@@ -78,6 +78,8 @@  do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
 #define SONIC_RWP    0x18
 #define SONIC_TRBA0  0x19
 #define SONIC_TRBA1  0x1a
+#define SONIC_TBWC0  0x1b
+#define SONIC_TBWC1  0x1c
 #define SONIC_LLFA   0x1f
 #define SONIC_TTDA   0x20
 #define SONIC_CEP    0x21
@@ -777,6 +779,8 @@  static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
     /* Save current position */
     s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
     s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
+    s->regs[SONIC_TBWC1] = s->regs[SONIC_RBWC1];
+    s->regs[SONIC_TBWC0] = s->regs[SONIC_RBWC0];
 
     /* Calculate the ethernet checksum */
     checksum = cpu_to_le32(crc32(0, buf, rx_len));
@@ -827,6 +831,12 @@  static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
     if (s->regs[SONIC_LLFA] & 0x1) {
         /* EOL detected */
         s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
+
+        /* Restore buffer state */
+        s->regs[SONIC_CRBA1] = s->regs[SONIC_TRBA1];
+        s->regs[SONIC_CRBA0] = s->regs[SONIC_TRBA0];
+        s->regs[SONIC_RBWC1] = s->regs[SONIC_TBWC1];
+        s->regs[SONIC_RBWC0] = s->regs[SONIC_TBWC0];
     } else {
         /* Clear in_use */
         int offset = dp8393x_crda(s) + sizeof(uint16_t) * 6 * width;