summaryrefslogtreecommitdiff
path: root/src/kernel/arch
diff options
context:
space:
mode:
authordzwdz2022-08-21 16:02:38 +0200
committerdzwdz2022-08-21 16:02:38 +0200
commitdc5098f83ac55722744a97d2950f50ef2a221f1a (patch)
treeb9f4f0f1172cb75abec3e355d4e7e72ebd1475ac /src/kernel/arch
parent2c3df5122edc3aaee5f8d3776a7d296310a5021e (diff)
amd64/rtl8139: fix incorrect ring buffer wrapping reads
I was reading from the buffer as if the WRAP flag was enabled, but it actually isn't supported with a 64K buffer. Besides, if it worked correctly, then the code for updating the ring position would land in the wrong place, because it didn't take WARP into account.
Diffstat (limited to 'src/kernel/arch')
-rw-r--r--src/kernel/arch/amd64/driver/rtl8139.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/src/kernel/arch/amd64/driver/rtl8139.c b/src/kernel/arch/amd64/driver/rtl8139.c
index e50fb63..fd7717f 100644
--- a/src/kernel/arch/amd64/driver/rtl8139.c
+++ b/src/kernel/arch/amd64/driver/rtl8139.c
@@ -32,7 +32,8 @@ static uint16_t iobase;
#define buflen_shift 3
#define rxbuf_baselen ((8 * 1024) << buflen_shift)
-static char rxbuf[rxbuf_baselen + 16 + 1500];
+/* the +16 is apparently required for... something */
+static char rxbuf[rxbuf_baselen + 16];
static size_t rxpos;
#define txbuf_len 2048
@@ -68,7 +69,6 @@ void rtl8139_init(uint32_t bdf) {
rcr |= 1 << 1; /* accept packets with our mac */
rcr |= 1 << 2; /* accept multicast */
rcr |= 1 << 3; /* accept broadcast */
- rcr |= 1 << 7; /* WARP */
rcr |= buflen_shift << 11;
rcr |= 7 << 13; /* no rx threshold, copy whole packets */
port_out32(iobase + RCR, rcr);
@@ -126,7 +126,13 @@ static int try_rx(struct pagedir *pages, void __user *dest, size_t dlen) {
// kprintf("packet size 0x%x, flags 0x%x, rxpos %x\n", size, flags, rxpos - 4);
if (dlen > size) dlen = size;
- virt_cpy_to(pages, dest, rxbuf + rxpos, dlen);
+ if (rxpos + dlen <= rxbuf_baselen) {
+ virt_cpy_to(pages, dest, rxbuf + rxpos, dlen);
+ } else {
+ size_t chunk = rxbuf_baselen - rxpos;
+ virt_cpy_to(pages, dest, rxbuf + rxpos, chunk);
+ virt_cpy_to(pages, dest + chunk, rxbuf, dlen - chunk);
+ }
rxpos += size;
rxpos = (rxpos + 3) & ~3;