From 80839982e9983c6ccadbf57a44e60eeb0e535421 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sat, 4 May 2024 20:26:13 +0200
Subject: kernel/rtl8139: prepare for /dev/eth/mac

---
 src/kernel/arch/amd64/driver/rtl8139.c | 110 +++++++++++++++++++++------------
 src/kernel/arch/amd64/driver/util.h    |   1 +
 2 files changed, 70 insertions(+), 41 deletions(-)

(limited to 'src/kernel/arch')

diff --git a/src/kernel/arch/amd64/driver/rtl8139.c b/src/kernel/arch/amd64/driver/rtl8139.c
index 42b2abb..d1054a4 100644
--- a/src/kernel/arch/amd64/driver/rtl8139.c
+++ b/src/kernel/arch/amd64/driver/rtl8139.c
@@ -1,3 +1,4 @@
+#include <camellia/errno.h>
 #include <kernel/arch/amd64/driver/driver.h>
 #include <kernel/arch/amd64/driver/util.h>
 #include <kernel/arch/amd64/interrupts.h>
@@ -16,18 +17,18 @@ static VfsReq *blocked_on = NULL;
 
 
 enum {
-	MAC = 0,
-	TXSTATUS0 = 0x10,
-	TXSTART0 = 0x20,
-	RBSTART = 0x30,
-	CMD = 0x37,
-	CAPR = 0x38,
-	CBR = 0x3A,
-	INTRMASK = 0x3C,
-	INTRSTATUS = 0x3E,
-	TCR = 0x40,
-	RCR = 0x44,
-	CONFIG1 = 0x52,
+	Mac = 0,
+	TxStatus0 = 0x10,
+	TxStart0 = 0x20,
+	RbStart = 0x30,
+	Cmd = 0x37,
+	Capr = 0x38,
+	Cbr = 0x3A,
+	IntrMask = 0x3C,
+	IntrStatus = 0x3E,
+	Tcr = 0x40,
+	Rcr = 0x44,
+	Config1 = 0x52,
 };
 
 static uint16_t iobase;
@@ -40,10 +41,11 @@ static size_t rxpos;
 
 #define txbuf_len 2048
 static char txbuf[4][txbuf_len];
+static uint8_t mac[6];
 
 static void rx_irq_enable(bool v) {
 	uint16_t mask = 1; /* rx ok */
-	port_out16(iobase + INTRMASK, v ? mask : 0);
+	port_out16(iobase + IntrMask, v ? mask : 0);
 }
 
 void rtl8139_init(uint32_t bdf) {
@@ -57,15 +59,15 @@ void rtl8139_init(uint32_t bdf) {
 	pcicfg_w32(bdf, PCICFG_CMD, cmd);
 
 
-	port_out8(iobase + CONFIG1, 0); /* power on */
+	port_out8(iobase + Config1, 0); /* power on */
 
-	port_out8(iobase + CMD, 0x10); /* software reset */
-	while (port_in8(iobase + CMD) & 0x10);
+	port_out8(iobase + Cmd, 0x10); /* software reset */
+	while (port_in8(iobase + Cmd) & 0x10);
 
 	assert((long)(void*)rxbuf <= 0xFFFFFFFF);
-	port_out32(iobase + RBSTART, (long)(void*)rxbuf);
+	port_out32(iobase + RbStart, (long)(void*)rxbuf);
 
-	port_out32(iobase + TCR, 0);
+	port_out32(iobase + Tcr, 0);
 
 	uint32_t rcr = 0;
 	// rcr |= 1 << 0; /* accept all packets */
@@ -74,17 +76,22 @@ void rtl8139_init(uint32_t bdf) {
 	rcr |= 1 << 3; /* accept broadcast */
 	rcr |= buflen_shift << 11;
 	rcr |= 7 << 13; /* no rx threshold, copy whole packets */
-	port_out32(iobase + RCR, rcr);
+	port_out32(iobase + Rcr, rcr);
 
-	port_out8(iobase + CMD, 0xC); /* enable RX TX */
+	port_out8(iobase + Cmd, 0xC); /* enable RX TX */
 
 	rx_irq_enable(false);
 
-	vfs_root_register("/dev/eth", accept);
+	for (int i = 0; i < 6; i++) {
+		mac[i] = port_in8(iobase + Mac + i);
+	}
+	kprintf("%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+	vfs_root_register("/dev/eth/", accept);
 }
 
 static void rtl8139_irq(void) {
-	uint16_t status = port_in16(iobase + INTRSTATUS);
+	uint16_t status = port_in16(iobase + IntrStatus);
 	if (!(status & 1)) {
 		kprintf("bad rtl8139 status 0x%x\n", status);
 		panic_unimplemented();
@@ -93,21 +100,21 @@ static void rtl8139_irq(void) {
 
 	/* bit 0 of cmd - Rx Buffer Empty
 	 * not a do while() because sometimes the bit is empty on IRQ. no clue why. */
-	while (!(port_in8(iobase + CMD) & 1)) {
+	while (!(port_in8(iobase + Cmd) & 1)) {
 		if (!postqueue_pop(&blocked_on, accept)) {
 			rx_irq_enable(false);
 			break;
 		}
 	}
 
-	//kprintf("rxpos %x cbr %x\n", rxpos, port_in16(iobase + CBR));
-	port_out16(iobase + INTRSTATUS, status);
+	//kprintf("rxpos %x cbr %x\n", rxpos, port_in16(iobase + Cbr));
+	port_out16(iobase + IntrStatus, status);
 }
 
 static int try_rx(Proc *proc, void __user *dest, size_t dlen) {
 	uint16_t flags, size;
 	/* bit 0 - Rx Buffer Empty */
-	if (port_in8(iobase + CMD) & 1) return WAIT;
+	if (port_in8(iobase + Cmd) & 1) return WAIT;
 
 	/* https://github.com/qemu/qemu/blob/04ddcda6a/hw/net/rtl8139.c#L1169 */
 	/* https://www.cs.usfca.edu/~cruse/cs326f04/RTL8139D_DataSheet.pdf page 12
@@ -136,7 +143,7 @@ static int try_rx(Proc *proc, void __user *dest, size_t dlen) {
 	rxpos = (rxpos + 3) & ~3;
 	while (rxpos >= rxbuf_baselen) rxpos -= rxbuf_baselen;
 	/* the device adds the 0x10 back, it's supposed to avoid overflow */
-	port_out16(iobase + CAPR, rxpos - 0x10);
+	port_out16(iobase + Capr, rxpos - 0x10);
 	return size;
 }
 
@@ -146,7 +153,7 @@ static int try_tx(Proc *proc, const void __user *src, size_t slen) {
 	if (slen > 0xFFF) return -1;
 	if (slen > txbuf_len) return -1;
 
-	uint32_t status = port_in32(iobase + TXSTATUS0 + desc*4);
+	uint32_t status = port_in32(iobase + TxStatus0 + desc*4);
 	if (!(status & (1<<13))) {
 		/* can't (?) be caused (and thus, tested) on a vm */
 		kprintf("try_tx called with all descriptors full.");
@@ -157,24 +164,40 @@ static int try_tx(Proc *proc, const void __user *src, size_t slen) {
 		return -1;
 	}
 	assert((long)(void*)txbuf <= 0xFFFFFFFF);
-	port_out32(iobase + TXSTART0  + desc*4, (long)(void*)txbuf[desc]);
-	port_out32(iobase + TXSTATUS0 + desc*4, slen);
+	port_out32(iobase + TxStart0  + desc*4, (long)(void*)txbuf[desc]);
+	port_out32(iobase + TxStatus0 + desc*4, slen);
 
 	desc = (desc + 1) & 3;
 	return slen;
 }
 
+enum {
+	HandleRoot,
+	HandleNet,
+};
+
 static void accept(VfsReq *req) {
+	long ret;
+	long id = (long __force)req->id;
+
 	if (!req->caller) {
 		vfsreq_finish_short(req, -1);
 		return;
 	}
+
 	switch (req->type) {
-		long ret;
-		case VFSOP_OPEN:
-			vfsreq_finish_short(req, req->input.len == 0 ? 0 : -1);
-			break;
-		case VFSOP_READ:
+	case VFSOP_OPEN:
+		if (reqpathcmp(req, "")) ret = HandleRoot;
+		else if (reqpathcmp(req, "net")) ret = HandleNet;
+		else ret = -ENOENT;
+		vfsreq_finish_short(req, ret);
+		break;
+	case VFSOP_READ:
+		if (id == HandleRoot) {
+			const char data[] = "net";
+			ret = req_readcopy(req, data, sizeof data);
+			vfsreq_finish_short(req, ret);
+		} else if (id == HandleNet) {
 			ret = try_rx(req->caller, req->output.buf, req->output.len);
 			if (ret == WAIT) {
 				postqueue_join(&blocked_on, req);
@@ -182,13 +205,18 @@ static void accept(VfsReq *req) {
 			} else {
 				vfsreq_finish_short(req, ret);
 			}
-			break;
-		case VFSOP_WRITE:
+		} else panic_invalid_state();
+		break;
+	case VFSOP_WRITE:
+		if (id == HandleNet) {
 			assert(!req->input.kern);
 			vfsreq_finish_short(req, try_tx(req->caller, req->input.buf, req->input.len));
-			break;
-		default:
-			vfsreq_finish_short(req, -1);
-			break;
+		} else {
+			vfsreq_finish_short(req, -ENOSYS);
+		}
+		break;
+	default:
+		vfsreq_finish_short(req, -1);
+		break;
 	}
 }
diff --git a/src/kernel/arch/amd64/driver/util.h b/src/kernel/arch/amd64/driver/util.h
index c49b859..6fae977 100644
--- a/src/kernel/arch/amd64/driver/util.h
+++ b/src/kernel/arch/amd64/driver/util.h
@@ -1,5 +1,6 @@
 #pragma once
 #include <kernel/types.h>
+#include <shared/mem.h>
 #include <shared/ring.h>
 #include <stdbool.h>
 #include <stddef.h>
-- 
cgit v1.2.3