summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-26 22:35:58 +0200
committerAnton Kling <anton@kling.gg>2023-10-30 21:49:48 +0100
commitf8e15da04472f5ed6a26e588de4a23cb3e1ba20b (patch)
tree9e646d6ba72dcc8f2eb95d04bac2a8b4a91ad946
parentcf60045bdb969f6fe44fe7dc9bf7cec593a0b05c (diff)
Kernel: Fixup rtl8139, add basic ARP and ethernet support
Currently the ARP appears to be able to respond to requests.
-rw-r--r--Makefile4
-rw-r--r--README.md7
-rw-r--r--drivers/rtl8139.c109
-rw-r--r--drivers/rtl8139.h3
-rw-r--r--network/arp.c83
-rw-r--r--network/arp.h3
-rw-r--r--network/bytes.c10
-rw-r--r--network/bytes.h5
-rw-r--r--network/ethernet.c101
-rw-r--r--network/ethernet.h5
10 files changed, 304 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index 49bbb94..04fad93 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
CC="./sysroot/bin/i686-sb-gcc"
AS="./sysroot/bin/i686-sb-as"
-OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o read_eip.o libc/exit/assert.o process.o cpu/int_syscall.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o halts.o scalls/ppoll.o scalls/ftruncate.o kubsan.o scalls/mmap.o drivers/serial.o scalls/accept.o scalls/bind.o scalls/socket.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o scalls/shm.o elf.o ksbrk.o sched/scheduler.o scalls/stat.o libc/string/copy.o libc/string/strncpy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o scalls/msleep.o scalls/uptime.o scalls/mkdir.o drivers/pci.o drivers/rtl8139.o
+OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o read_eip.o libc/exit/assert.o process.o cpu/int_syscall.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o halts.o scalls/ppoll.o scalls/ftruncate.o kubsan.o scalls/mmap.o drivers/serial.o scalls/accept.o scalls/bind.o scalls/socket.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o scalls/shm.o elf.o ksbrk.o sched/scheduler.o scalls/stat.o libc/string/copy.o libc/string/strncpy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o scalls/msleep.o scalls/uptime.o scalls/mkdir.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o
CFLAGS = -O2 -fsanitize=vla-bound,shift-exponent,pointer-overflow,shift,signed-integer-overflow,bounds -ggdb -ffreestanding -Wall -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I.
INCLUDE=-I./includes/ -I./libc/include/
@@ -23,7 +23,7 @@ nk:
qemu-system-i386 -d int -no-reboot -no-shutdown -serial file:./serial.log -hda ext2.img -m 1G -cdrom myos.iso -s
run:
- qemu-system-i386 -enable-kvm -d int -no-reboot -no-shutdown -chardev stdio,id=char0,logfile=serial.log,signal=off -serial chardev:char0 -hda ext2.img -m 1G -cdrom myos.iso -s
+ qemu-system-i386 -enable-kvm -netdev user,id=n0,hostfwd=udp:127.0.0.1:6001-:6000 -device rtl8139,netdev=n0 -d int -no-reboot -no-shutdown -chardev stdio,id=char0,logfile=serial.log,signal=off -serial chardev:char0 -hda ext2.img -m 1G -cdrom myos.iso -s
myos.iso: myos.bin
cp myos.bin isodir/boot
diff --git a/README.md b/README.md
index 0a6aa67..03340c3 100644
--- a/README.md
+++ b/README.md
@@ -19,9 +19,16 @@ as GRUB).
* libc
* Window Manager
* Terminal Emulator
+* Simple Text Editor(ante)
* Very basic shell
* Shell utilities(cat, yes, echo etc)
+### WIP
+
+* PCI (somewhat functional for current use)
+* rtl8139 Network Card (approaching somewhat complete)
+* ARP/Ethernet/IPv4 very much not complete
+
and some other stuff.
## Screenshot
diff --git a/drivers/rtl8139.c b/drivers/rtl8139.c
index 0d665b1..0c1606b 100644
--- a/drivers/rtl8139.c
+++ b/drivers/rtl8139.c
@@ -4,6 +4,7 @@
#include <drivers/pci.h>
#include <drivers/rtl8139.h>
#include <mmu.h>
+#include <network/ethernet.h>
#define RBSTART 0x30
#define CMD 0x37
@@ -13,31 +14,84 @@
#define TSAD0 0x20 // transmit start address
struct PCI_DEVICE rtl8139;
-uint8_t device_buffer[8192 + 16];
-uint32_t g_base_address;
+uint8_t *device_buffer;
uint8_t *send_buffers[4];
-#define ROK (1 << 0)
-#define TOK (1 << 2)
+struct _INT_PACKET_HEADER {
+ uint8_t ROK : 1;
+ uint8_t FAE : 1;
+ uint8_t CRC : 1;
+ uint8_t LONG : 1;
+ uint8_t RUNT : 1;
+ uint8_t ISE : 1;
+ uint8_t reserved : 5;
+ uint8_t BAR : 1;
+ uint8_t PAM : 1;
+ uint8_t MAR : 1;
+};
+
+struct PACKET_HEADER {
+ union {
+ uint16_t raw;
+ struct _INT_PACKET_HEADER data;
+ };
+};
+
+uint16_t current_packet_read = 0;
+
+void handle_packet(void) {
+ assert(sizeof(struct _INT_PACKET_HEADER) == sizeof(uint16_t));
+
+ uint16_t *buf = (uint16_t *)(device_buffer + current_packet_read);
+ struct PACKET_HEADER packet_header;
+ packet_header.raw = *buf;
+ assert(packet_header.data.ROK);
+ kprintf("packet_header.raw: %x\n", packet_header.raw);
+ uint16_t packet_length = *(buf + 1);
+ kprintf("packet_length: %x\n", packet_length);
+
+ uint8_t packet_buffer[8192 + 16];
+ if (current_packet_read + packet_length >= 8192 + 16) {
+ uint32_t first_run = ((uint8_t *)buf + (8192 + 16)) - device_buffer;
+ memcpy(packet_buffer, buf, first_run);
+ memcpy(packet_buffer, device_buffer, packet_length - first_run);
+ } else {
+ memcpy(packet_buffer, buf, packet_length);
+ }
+
+ handle_ethernet((uint8_t *)packet_buffer + 4, packet_length);
+
+ // Thanks to exscape
+ // https://github.com/exscape/exscapeOS/blob/master/src/kernel/net/rtl8139.c
+ // and the programmers guide
+ // https://www.cs.usfca.edu/~cruse/cs326f04/RTL8139_ProgrammersGuide.pdf I
+ // have no clue what this calculation, I can't find anything possibly relating
+ // to this in the manual, but it does work I guess.
+ current_packet_read = (current_packet_read + packet_length + 4 + 3) & (~3);
+ current_packet_read %= 8192 + 16;
+ outw(rtl8139.gen.base_mem_io + 0x38, current_packet_read - 0x10);
+}
__attribute__((interrupt)) void rtl8139_handler(void *regs) {
(void)regs;
uint16_t status = inw(rtl8139.gen.base_mem_io + 0x3e);
+ kprintf("status: %x\n", status);
- if (status & TOK) {
+ outw(rtl8139.gen.base_mem_io + 0x3E, 0x5);
+ if (status & (1 << 2)) {
kprintf("Packet sent\n");
}
- if (status & ROK) {
+ if (status & (1 << 0)) {
kprintf("Received packet\n");
+ handle_packet();
}
- outw(rtl8139.gen.base_mem_io + 0x3E, 0x5);
EOI(0xB);
}
-int rtl8139_send_data(const struct PCI_DEVICE *device, uint8_t *data,
- uint16_t data_size) {
+int rtl8139_send_data(uint8_t *data, uint16_t data_size) {
+ const struct PCI_DEVICE *device = &rtl8139;
// FIXME: It should block or fail if there is too little space for the
// buffer
if (data_size > 0x1000)
@@ -54,6 +108,19 @@ int rtl8139_send_data(const struct PCI_DEVICE *device, uint8_t *data,
return 1;
}
+void get_mac_address(uint8_t mac[6]) {
+ uint32_t base_address = rtl8139.gen.base_mem_io;
+ // Read the MAC address
+ uint64_t mac_address;
+ {
+ uint32_t low_mac = inl(base_address);
+ uint16_t high_mac = inw(base_address + 0x4);
+ mac_address = ((uint64_t)high_mac << 32) | low_mac;
+ }
+ kprintf("mac_address: %x\n", mac_address);
+ memcpy(mac, &mac_address, sizeof(uint8_t[6]));
+}
+
uint8_t rtl8139_get_transmit_status(uint32_t base_address) {
uint32_t status_register = inl(base_address + 0x3E);
if ((status_register >> 3) & 0x1)
@@ -76,14 +143,10 @@ void rtl8139_init(void) {
uint32_t base_address = rtl8139.gen.base_mem_io;
uint8_t interrupt_line = pci_get_interrupt_line(&rtl8139);
- // Read the MAC address
- uint64_t mac_address;
- {
- uint32_t low_mac = inl(base_address);
- uint16_t high_mac = inw(base_address + 0x4);
- mac_address = ((uint64_t)high_mac << 32) | low_mac;
- }
- kprintf("mac_address: %x\n", mac_address);
+ // Enable bus mastering
+ uint32_t register1 = pci_config_read32(&rtl8139, 0, 0x4);
+ register1 |= (1 << 2);
+ pci_config_write32(&rtl8139, 0, 0x4, register1);
// Turning on the device
outb(base_address + 0x52, 0x0);
@@ -92,19 +155,21 @@ void rtl8139_init(void) {
outb(base_address + CMD, 0x10);
for (; 0 != (inb(base_address + CMD) & 0x10);)
;
-
+ device_buffer = ksbrk(8192 + 16);
+ memset(device_buffer, 0, 8192 + 16);
// Setupt the recieve buffer
uint32_t rx_buffer = (uint32_t)virtual_to_physical(device_buffer, NULL);
outl(base_address + RBSTART, rx_buffer);
// Set IMR + ISR
- outw(base_address + IMR, (1 << 2) | (1 << 3));
+ outw(base_address + IMR, (1 << 2) | (1 << 3) | (1 << 0));
+ // Set transmit and reciever enable
outb(base_address + 0x37, (1 << 2) | (1 << 3));
// Configure the recieve buffer
outl(base_address + 0x44,
- 0xf | (1 << 7)); // (1 << 7) is the WRAP bit, 0xf is AB+AM+APM+AAP
+ 0xf); // 0xf is AB+AM+APM+AAP
install_handler(rtl8139_handler, INT_32_INTERRUPT_GATE(0x0),
0x20 + interrupt_line);
@@ -114,10 +179,6 @@ void rtl8139_init(void) {
for (int i = 0; i < 4; i++)
send_buffers[i] = ksbrk(0x1000);
asm("sti");
- for (int i = 0; i < 10; i++) {
- char buffer[512];
- rtl8139_send_data(&rtl8139, (uint8_t *)buffer, 512);
- }
for (;;)
asm("sti");
}
diff --git a/drivers/rtl8139.h b/drivers/rtl8139.h
index 1f3d84e..6e13fdd 100644
--- a/drivers/rtl8139.h
+++ b/drivers/rtl8139.h
@@ -1 +1,4 @@
+#include <stdint.h>
+void get_mac_address(uint8_t mac[6]);
void rtl8139_init(void);
+int rtl8139_send_data(uint8_t *data, uint16_t data_size);
diff --git a/network/arp.c b/network/arp.c
new file mode 100644
index 0000000..eb8aca3
--- /dev/null
+++ b/network/arp.c
@@ -0,0 +1,83 @@
+#include <assert.h>
+#include <drivers/rtl8139.h>
+#include <network/arp.h>
+#include <network/bytes.h>
+#include <network/ethernet.h>
+#include <stdio.h>
+#include <string.h>
+
+struct ARP_DATA {
+ uint16_t htype; // Hardware type
+ uint16_t ptype; // Protocol type
+ uint8_t hlen; // Hardware address length (Ethernet = 6)
+ uint8_t plen; // Protocol address length (IPv4 = 4)
+ uint16_t opcode; // ARP Operation Code
+ uint8_t srchw[6]; // Source hardware address - hlen bytes (see above)
+ uint8_t srcpr[4]; // Source protocol address - plen bytes (see above).
+ // If IPv4 can just be a "u32" type.
+ uint8_t dsthw[6]; // Destination hardware address - hlen bytes (see above)
+ uint8_t dstpr[4]; // Destination protocol address - plen bytes (see
+ // above). If IPv4 can just be a "u32" type.
+};
+
+// FIXME: This is hardcoded, don't do this.
+uint8_t ip_address[4] = {10, 0, 2, 15};
+
+void print_mac(const char *str, uint8_t *mac) {
+ kprintf("%s: ", str);
+ for (int i = 0; i < 6; i++) {
+ kprintf("%x", mac[i]);
+ if (5 != i)
+ kprintf(":");
+ }
+ kprintf("\n");
+}
+
+void print_ip(const char *str, uint8_t *ip) {
+ kprintf("%s: ", str);
+ for (int i = 0; i < 4; i++) {
+ kprintf("%d", ip[i]);
+ if (3 != i)
+ kprintf(".");
+ }
+ kprintf("\n");
+}
+
+void handle_arp(uint8_t *payload) {
+ struct ARP_DATA *data = (struct ARP_DATA *)payload;
+
+ // Assert that communication is over ethernet
+ assert(1 == ntohs(data->htype));
+ // Assert it is a request
+ assert(0x0001 == ntohs(data->opcode));
+ // Assert that request uses IP
+ assert(0x0800 == ntohs(data->ptype));
+
+ assert(6 == data->hlen);
+ assert(4 == data->plen);
+ print_mac("srchw: ", data->srchw);
+ print_ip("srcpr: ", data->srcpr);
+
+ print_mac("dsthw: ", data->dsthw);
+ print_ip("dstpr: ", data->dstpr);
+
+ uint8_t mac[6];
+ get_mac_address(mac);
+ print_mac("THIS DEVICE MAC: ", mac);
+ assert(0 == memcmp(data->dstpr, ip_address, sizeof(uint8_t[4])));
+
+ // Now we have to construct a ARP response
+ struct ARP_DATA response;
+ response.htype = htons(1);
+ response.ptype = htons(0x0800);
+ response.opcode = htons(0x00002);
+ response.hlen = 6;
+ response.plen = 4;
+ get_mac_address(response.srchw);
+ memcpy(response.srcpr, ip_address, sizeof(uint8_t[4]));
+
+ memcpy(response.dsthw, data->srchw, sizeof(uint8_t[6]));
+ memcpy(response.dstpr, data->srcpr, sizeof(uint8_t[4]));
+
+ send_ethernet_packet(data->srchw, 0x0806, (uint8_t*)&response, sizeof(response));
+}
diff --git a/network/arp.h b/network/arp.h
new file mode 100644
index 0000000..1e8df1b
--- /dev/null
+++ b/network/arp.h
@@ -0,0 +1,3 @@
+#include <stdint.h>
+
+void handle_arp(uint8_t *payload);
diff --git a/network/bytes.c b/network/bytes.c
new file mode 100644
index 0000000..94afa73
--- /dev/null
+++ b/network/bytes.c
@@ -0,0 +1,10 @@
+#include <network/bytes.h>
+
+uint16_t ntohs(uint16_t net) { return (net >> 8) | (net << 8); }
+
+uint16_t htons(uint16_t net) { return (net >> 8) | (net << 8); }
+
+uint32_t htonl(uint32_t net) {
+ return (((net & 0x000000FF) << 24) | ((net & 0x0000FF00) << 8) |
+ ((net & 0x00FF0000) >> 8) | ((net & 0xFF000000) >> 24));
+}
diff --git a/network/bytes.h b/network/bytes.h
new file mode 100644
index 0000000..c291589
--- /dev/null
+++ b/network/bytes.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+
+uint16_t ntohs(uint16_t net);
+uint16_t htons(uint16_t net);
+uint32_t htonl(uint32_t net);
diff --git a/network/ethernet.c b/network/ethernet.c
new file mode 100644
index 0000000..ae8e814
--- /dev/null
+++ b/network/ethernet.c
@@ -0,0 +1,101 @@
+#include <assert.h>
+#include <drivers/rtl8139.h>
+#include <kmalloc.h>
+#include <network/arp.h>
+#include <network/bytes.h>
+#include <network/ethernet.h>
+#include <stdio.h>
+
+struct ETHERNET_HEADER {
+ uint8_t mac_dst[6];
+ uint8_t mac_src[6];
+ uint16_t type;
+};
+
+uint32_t crc32(const char *buf, size_t len) {
+ static uint32_t table[256];
+ static int have_table = 0;
+ uint32_t rem;
+ uint8_t octet;
+ int i, j;
+ const char *p, *q;
+
+ if (have_table == 0) {
+ for (i = 0; i < 256; i++) {
+ rem = i;
+ for (j = 0; j < 8; j++) {
+ if (rem & 1) {
+ rem >>= 1;
+ rem ^= 0xedb88320;
+ } else
+ rem >>= 1;
+ }
+ table[i] = rem;
+ }
+ have_table = 1;
+ }
+
+ uint32_t crc = 0xFFFFFFFF;
+ q = buf + len;
+ for (p = buf; p < q; p++) {
+ octet = *p;
+ crc = (crc >> 8) ^ table[(crc & 0xff) ^ octet];
+ }
+ return ~crc;
+}
+
+void handle_ethernet(uint8_t *packet, uint64_t packet_length) {
+ struct ETHERNET_HEADER *eth_header = (struct ETHERNET_HEADER *)packet;
+ packet += sizeof(struct ETHERNET_HEADER);
+ uint8_t *payload = packet;
+ packet += packet_length - sizeof(struct ETHERNET_HEADER);
+ uint32_t crc = *((uint32_t *)packet - 1);
+ kprintf("PACKET crc: %x\n", crc);
+ kprintf("OUR OWN CALCULATED crc: %x\n",
+ crc32((const char *)eth_header, (packet_length - 4)));
+
+ kprintf("mac dst: ");
+ for (int i = 0; i < 6; i++)
+ kprintf("%x", eth_header->mac_dst[i]);
+ kprintf("\n");
+ kprintf("mac src: ");
+ for (int i = 0; i < 6; i++)
+ kprintf("%x", eth_header->mac_src[i]);
+ kprintf("\n");
+
+ uint16_t type = ntohs(eth_header->type);
+ kprintf("Etheretype: %x\n", type);
+ switch (type) {
+ case 0x0806:
+ handle_arp(payload);
+ break;
+ case 0x0800:
+ kprintf("IPV4 message\n");
+ break;
+ default:
+ kprintf("Can't handle ethernet type\n");
+ break;
+ }
+}
+
+void send_ethernet_packet(uint8_t mac_dst[6], uint16_t type, uint8_t *payload,
+ uint64_t payload_length) {
+ // FIXME: Janky allocation, do this better
+ uint64_t buffer_size =
+ sizeof(struct ETHERNET_HEADER) + payload_length + sizeof(uint32_t);
+ uint8_t *buffer = kmalloc(buffer_size);
+ uint8_t *buffer_start = buffer;
+ struct ETHERNET_HEADER *eth_header = (struct ETHERNET_HEADER *)buffer;
+ buffer += sizeof(struct ETHERNET_HEADER);
+ memcpy(buffer, payload, payload_length);
+ buffer += payload_length;
+
+ memcpy(eth_header->mac_dst, mac_dst, sizeof(uint8_t[6]));
+ get_mac_address(eth_header->mac_src);
+ eth_header->type = htons(type);
+ *(uint32_t *)(buffer) =
+ htonl(crc32((const char *)buffer_start, buffer_size - 4));
+
+ assert(rtl8139_send_data(buffer_start, buffer_size));
+ kprintf("sent data\n");
+}
diff --git a/network/ethernet.h b/network/ethernet.h
new file mode 100644
index 0000000..88a4dc6
--- /dev/null
+++ b/network/ethernet.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+
+void handle_ethernet(uint8_t *packet, uint64_t packet_length);
+void send_ethernet_packet(uint8_t mac_dst[6], uint16_t type, uint8_t *payload,
+ uint64_t payload_length);