From 86eb7c9282949166bfa1f4af48d99dc13643daed Mon Sep 17 00:00:00 2001 From: Mark Date: Thu, 19 Mar 2020 16:41:05 +0200 Subject: [PATCH] Add RTL8139 receive and network daemon with stub handler --- drivers/net/rtl8139.c | 142 ++++++++++++++++++++++++++++++++++++++++++ etc/make/conf.mk | 6 ++ include/net/net.h | 6 ++ net/net.c | 26 ++++++++ sys/kernel.c | 2 + 5 files changed, 182 insertions(+) create mode 100644 drivers/net/rtl8139.c create mode 100644 include/net/net.h create mode 100644 net/net.c diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c new file mode 100644 index 0000000..dabddfe --- /dev/null +++ b/drivers/net/rtl8139.c @@ -0,0 +1,142 @@ +#include "arch/amd64/mm/phys.h" +#include "arch/amd64/hw/io.h" +#include "drivers/pci/pci.h" +#include "sys/assert.h" +#include "sys/debug.h" +#include "sys/heap.h" +#include "sys/attr.h" +#include "net/net.h" +#include "sys/mm.h" + +#define CR_RST (1 << 4) +#define CR_RE (1 << 3) +#define CR_BUFE (1 << 0) + +#define IMR_ROK (1 << 0) +#define IMR_RER (1 << 1) + +#define ISR_ROK (1 << 0) +#define ISR_RER (1 << 1) + +#define RCR_WRAP (1 << 7) +#define RCR_AR (1 << 4) +#define RCR_AB (1 << 3) // Broadcast +#define RCR_AM (1 << 2) // Multicast +#define RCR_APM (1 << 1) // Physical Match +#define RCR_AAP (1 << 0) // All + +#define REG_IDR(i) ((i)) +#define REG_RBSTART 0x30 +#define REG_CAPR 0x38 +#define REG_CBR 0x3A +#define REG_CR 0x37 +#define REG_IMR 0x3C +#define REG_ISR 0x3E +#define REG_RCR 0x44 +#define REG_CONFIG0 0x51 +#define REG_CONFIG1 0x52 + +struct rtl8139 { + struct pci_device *dev; + + uintptr_t recv_buf_phys; + uint16_t rx_pos; + + uint8_t hwaddr[6]; + uint16_t iobase; +}; + +static void rtl8139_reset(struct rtl8139 *rtl) { + // Power on + outb(rtl->iobase + REG_CONFIG1, 0); + + // Software reset + outb(rtl->iobase + REG_CR, CR_RST); + while (inb(rtl->iobase + REG_CR) & CR_RST); +} + +static uint32_t rtl8139_irq(void *ctx) { + struct rtl8139 *rtl = ctx; + uint16_t isr = inw(rtl->iobase + REG_ISR); + uint32_t ret = IRQ_UNHANDLED; + + if (isr & ISR_ROK) { + uint16_t cbr = inw(rtl->iobase + REG_CBR); + uint16_t pkt_size; + void *rx_buf = (void *) MM_VIRTUALIZE(rtl->recv_buf_phys); + + while ((inw(rtl->iobase + REG_CR) & CR_BUFE) == 0) { + // Header: 4 bytes, I guess XXX + uint16_t rx_len = ((uint16_t *) (rx_buf + rtl->rx_pos))[1]; + void *data = rx_buf + rtl->rx_pos + 4; + + net_receive(rtl, data, rx_len); + + // Stolen this from somewhere + rtl->rx_pos = (rtl->rx_pos + rx_len + 4 + 3) & ~3; + outw(rtl->iobase + REG_CAPR, rtl->rx_pos - 0x10); + rtl->rx_pos %= 0x2000; + } + + ret = IRQ_HANDLED; + outw(rtl->iobase + REG_ISR, ISR_ROK); + } else { + kinfo("???\n"); + } + + return ret; +} + +static void rtl8139_init(struct pci_device *dev) { + struct rtl8139 *rtl = kmalloc(sizeof(struct rtl8139)); + uint32_t bar0, cmd; + uint16_t w0; + _assert(rtl); + + rtl->dev = dev; + + rtl->rx_pos = 0; + + // Allocate 12288 bytes (3 pages) + rtl->recv_buf_phys = amd64_phys_alloc_contiguous(3); + _assert(rtl->recv_buf_phys != MM_NADDR); + + // Enable device bus mastering + cmd = pci_config_read_dword(dev, PCI_CONFIG_CMD); + cmd |= 1 << 2; + pci_config_write_dword(dev, PCI_CONFIG_CMD, cmd); + + bar0 = pci_config_read_dword(dev, PCI_CONFIG_BAR(0)); + _assert((bar0 & 1)); + // 0xFFFF & ~0x3 + rtl->iobase = bar0 & 0xFFFC; + + rtl8139_reset(rtl); + + // Read MAC + for (size_t i = 0; i < 6; ++i) { + rtl->hwaddr[i] = inb(rtl->iobase + REG_IDR(i)); + } + kdebug("hwaddr: %02x:%02x:%02x:%02x:%02x:%02x\n", + rtl->hwaddr[0], rtl->hwaddr[1], rtl->hwaddr[2], + rtl->hwaddr[3], rtl->hwaddr[4], rtl->hwaddr[5]); + + // RBSTART + outl(rtl->iobase + REG_RBSTART, rtl->recv_buf_phys); + + // Unmask IRQs + outw(rtl->iobase + REG_IMR, IMR_ROK | IMR_RER); + outw(rtl->iobase + REG_ISR, 0); + + // Set RCR to receive all + outl(rtl->iobase + REG_RCR, RCR_WRAP | RCR_AB | RCR_APM | RCR_AAP | RCR_AM); + + // Enable receiver + outb(rtl->iobase + REG_CR, CR_RE); + + pci_add_irq(dev, rtl8139_irq, rtl); +} + +static __init void rtl8139_register(void) { + pci_add_device_driver(PCI_ID(0x10EC, 0x8139), rtl8139_init, "rtl8139"); +} diff --git a/etc/make/conf.mk b/etc/make/conf.mk index 0a675e7..cdccd54 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -92,6 +92,12 @@ DIRS+=$(O)/drivers/pci \ $(O)/drivers/ata \ $(O)/drivers/usb +OBJS+=$(O)/drivers/net/rtl8139.o +DIRS+=$(O)/drivers/net + +OBJS+=$(O)/net/net.o +DIRS+=$(O)/net + ifeq ($(DEBUG_COUNTERS),1) CFLAGS+=-DDEBUG_COUNTERS endif diff --git a/include/net/net.h b/include/net/net.h new file mode 100644 index 0000000..9016323 --- /dev/null +++ b/include/net/net.h @@ -0,0 +1,6 @@ +#pragma once +#include "sys/types.h" + +int net_receive(/* TODO: replace with struct netdev * */ void *ctx, const void *data, size_t len); + +int net_daemon_start(void); diff --git a/net/net.c b/net/net.c new file mode 100644 index 0000000..c4675f2 --- /dev/null +++ b/net/net.c @@ -0,0 +1,26 @@ +#include "sys/thread.h" +#include "sys/assert.h" +#include "sys/sched.h" +#include "sys/panic.h" +#include "sys/debug.h" + +static struct thread netd_thread = {0}; + + +static void net_daemon(void) { + while (1) { + asm volatile ("sti; hlt"); + } +} + +int net_receive(/* TODO: replace with struct netdev * */ void *ctx, const void *data, size_t len) { + kdebug("%u bytes\n", len); + debug_dump(DEBUG_DEFAULT, data, len); + return 0; +} + +void net_daemon_start(void) { + _assert(thread_init(&netd_thread, (uintptr_t) net_daemon, NULL, 0) == 0); + netd_thread.pid = thread_alloc_pid(0); + sched_queue(&netd_thread); +} diff --git a/sys/kernel.c b/sys/kernel.c index 7042e52..5f6c95f 100644 --- a/sys/kernel.c +++ b/sys/kernel.c @@ -6,6 +6,7 @@ #include "sys/panic.h" #include "fs/sysfs.h" #include "sys/init.h" +#include "net/net.h" #include "fs/tar.h" #include "fs/vfs.h" @@ -22,6 +23,7 @@ void main(void) { sched_init(); usb_daemon_start(); + net_daemon_start(); user_init_start(); sched_enter();