diff --git a/Makefile b/Makefile index f4e8aa0..0ead99f 100644 --- a/Makefile +++ b/Makefile @@ -119,4 +119,5 @@ clean: run: $(ISO_IMAGE) qemu-system-x86_64 -m 2G -serial stdio -cdrom $(ISO_IMAGE) -boot d \ - -audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 + -audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \ + -netdev user,id=net0 -device e1000,netdev=net0 diff --git a/README.md b/README.md index 2aed983..2b02f66 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Brew OS 1.03 Pre-Alpha +# Brew OS 1.10 Alpha ## Brewkernel is now BrewOS! Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion). @@ -9,6 +9,7 @@ Brew Kernel is a simple x86_64 hobbyist operating system. It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more! ## Features +- Basic Networking Stack - Brew WM - Fat 32 FS - 64-bit long mode support diff --git a/brewos.iso b/brewos.iso index cbd9ab5..6b0170e 100644 Binary files a/brewos.iso and b/brewos.iso differ diff --git a/build/brewos.elf b/build/brewos.elf index 73156f2..eacafee 100755 Binary files a/build/brewos.elf and b/build/brewos.elf differ diff --git a/build/cli_apps/net.o b/build/cli_apps/net.o new file mode 100644 index 0000000..73c2798 Binary files /dev/null and b/build/cli_apps/net.o differ diff --git a/build/cli_apps/pci_list.o b/build/cli_apps/pci_list.o new file mode 100644 index 0000000..df733a7 Binary files /dev/null and b/build/cli_apps/pci_list.o differ diff --git a/build/cmd.o b/build/cmd.o index 5290ca9..ede5399 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/e1000.o b/build/e1000.o new file mode 100644 index 0000000..efe2821 Binary files /dev/null and b/build/e1000.o differ diff --git a/build/idt.o b/build/idt.o index fe1073b..4f13af2 100644 Binary files a/build/idt.o and b/build/idt.o differ diff --git a/build/main.o b/build/main.o index 584e3e4..9ae7591 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/network.o b/build/network.o new file mode 100644 index 0000000..ed2877f Binary files /dev/null and b/build/network.o differ diff --git a/build/pci.o b/build/pci.o new file mode 100644 index 0000000..284b0aa Binary files /dev/null and b/build/pci.o differ diff --git a/build/platform.o b/build/platform.o new file mode 100644 index 0000000..e63f482 Binary files /dev/null and b/build/platform.o differ diff --git a/build/ps2.o b/build/ps2.o index 18a9495..f2832c9 100644 Binary files a/build/ps2.o and b/build/ps2.o differ diff --git a/build/wm.o b/build/wm.o index 8ecf201..0e2afa5 100644 Binary files a/build/wm.o and b/build/wm.o differ diff --git a/iso_root/README.md b/iso_root/README.md index 916502b..2aed983 100644 --- a/iso_root/README.md +++ b/iso_root/README.md @@ -1,4 +1,4 @@ -# Brew OS 1.01 Alpha +# Brew OS 1.03 Pre-Alpha ## Brewkernel is now BrewOS! Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion). diff --git a/iso_root/brewos.elf b/iso_root/brewos.elf index 73156f2..eacafee 100755 Binary files a/iso_root/brewos.elf and b/iso_root/brewos.elf differ diff --git a/src/kernel/about.c b/src/kernel/about.c index 145dc07..0deffd4 100644 --- a/src/kernel/about.c +++ b/src/kernel/about.c @@ -35,8 +35,8 @@ static void about_paint(Window *win) { // Version info draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK); - draw_string(offset_x, offset_y + 120, "BrewOS Version 1.03", COLOR_BLACK); - draw_string(offset_x, offset_y + 135, "Kernel Version 2.0.3", COLOR_BLACK); + draw_string(offset_x, offset_y + 120, "BrewOS Version 1.10", COLOR_BLACK); + draw_string(offset_x, offset_y + 135, "Kernel Version 2.1.0", COLOR_BLACK); // Copyright draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK); diff --git a/src/kernel/cli_apps/about.c b/src/kernel/cli_apps/about.c index e3a05c7..ebc7100 100644 --- a/src/kernel/cli_apps/about.c +++ b/src/kernel/cli_apps/about.c @@ -2,6 +2,6 @@ void cli_cmd_brewver(char *args) { (void)args; - cli_write("BrewOS v1.03 Alpha\n"); - cli_write("BrewOS Kernel V2.0.3 Pre-Alpha\n"); + cli_write("BrewOS v1.10 Alpha\n"); + cli_write("BrewOS Kernel V2.1.0 Pre-Alpha\n"); } diff --git a/src/kernel/cli_apps/cli_apps.h b/src/kernel/cli_apps/cli_apps.h index 55614c2..129c823 100644 --- a/src/kernel/cli_apps/cli_apps.h +++ b/src/kernel/cli_apps/cli_apps.h @@ -37,4 +37,14 @@ void cli_cmd_memblock(char *args); void cli_cmd_memvalid(char *args); void cli_cmd_memtest(char *args); +// Network commands +void cli_cmd_netinit(char *args); +void cli_cmd_netinfo(char *args); +void cli_cmd_ipset(char *args); +void cli_cmd_udpsend(char *args); +void cli_cmd_udptest(char *args); + +// PCI commands +void cli_cmd_pcilist(char *args); + #endif diff --git a/src/kernel/cli_apps/net.c b/src/kernel/cli_apps/net.c new file mode 100644 index 0000000..cba41f2 --- /dev/null +++ b/src/kernel/cli_apps/net.c @@ -0,0 +1,112 @@ +#include "cli_utils.h" +#include "network.h" + +static void print_mac(const mac_address_t* mac){ + char buf[64]; + int p=0; + for(int i=0;i<6;i++){ + int v=mac->bytes[i]; + int hi=(v>>4)&0xF, lo=v&0xF; + buf[p++]= (hi<10)?('0'+hi):('A'+(hi-10)); + buf[p++]= (lo<10)?('0'+lo):('A'+(lo-10)); + if(i<5) buf[p++]=':'; + } + buf[p]=0; + cli_write(buf); +} + +void cli_cmd_netinit(char *args){ + (void)args; + int r=network_init(); + if(r==0){ + cli_write("Network initialized\n"); + int d=network_dhcp_acquire(); + if(d==0){ + cli_write("DHCP acquired\n"); + } else { + cli_write("DHCP failed\n"); + } + } else { + cli_write("Network init failed\n"); + } +} + +void cli_cmd_netinfo(char *args){ + (void)args; + mac_address_t mac; + ipv4_address_t ip; + if(network_get_mac_address(&mac)==0){ + cli_write("MAC: "); print_mac(&mac); cli_write("\n"); + } + if(network_get_ipv4_address(&ip)==0){ + cli_write("IP: "); + for(int i=0;i<4;i++){ cli_write_int(ip.bytes[i]); if(i<3) cli_write("."); } + cli_write("\n"); + } + cli_write("Frames: "); cli_write_int(network_get_frames_received()); cli_write("\n"); + cli_write("UDP packets: "); cli_write_int(network_get_udp_packets_received()); cli_write("\n"); + cli_write("UDP callbacks: "); cli_write_int(network_get_udp_callbacks_called()); cli_write("\n"); + cli_write("E1000 receive calls: "); cli_write_int(network_get_e1000_receive_calls()); cli_write("\n"); + cli_write("E1000 receive empty: "); cli_write_int(network_get_e1000_receive_empty()); cli_write("\n"); + cli_write("Process calls: "); cli_write_int(network_get_process_calls()); cli_write("\n"); +} + +void cli_cmd_ipset(char *args){ + if(!args||!*args){ cli_write("Usage: IPSET a.b.c.d\n"); return; } + ipv4_address_t ip={{0,0,0,0}}; + int part=0; int val=0; int i=0; + while(args[i]){ + char ch=args[i++]; + if(ch>='0'&&ch<='9'){ val=val*10+(ch-'0'); if(val>255){ cli_write("Invalid IP\n"); return; } } + else if(ch=='.'){ if(part>3){ cli_write("Invalid IP\n"); return; } ip.bytes[part++]=(uint8_t)val; val=0; } + else { cli_write("Invalid IP\n"); return; } + } + if(part!=3){ cli_write("Invalid IP\n"); return; } + ip.bytes[3]=(uint8_t)val; + if(network_set_ipv4_address(&ip)==0){ cli_write("IP set\n"); } else { cli_write("IP set failed\n"); } +} + +void cli_cmd_udpsend(char *args){ + if(!args||!*args){ cli_write("Usage: UDPSEND ip port data\n"); return; } + char ipstr[32]; int pos=0; + while(args[pos] && args[pos]!=' '){ ipstr[pos]=args[pos]; pos++; } + ipstr[pos]=0; + while(args[pos]==' ') pos++; + char portstr[16]; int p=0; + while(args[pos] && args[pos]!=' '){ portstr[p++]=args[pos++]; } + portstr[p]=0; + while(args[pos]==' ') pos++; + char* datastr = args+pos; + ipv4_address_t ip={{0,0,0,0}}; + int idx=0; int val=0; int j=0; + while(ipstr[j]){ + char ch=ipstr[j++]; + if(ch>='0'&&ch<='9'){ val=val*10+(ch-'0'); if(val>255){ cli_write("Invalid IP\n"); return; } } + else if(ch=='.'){ if(idx>3){ cli_write("Invalid IP\n"); return; } ip.bytes[idx++]=(uint8_t)val; val=0; } + else { cli_write("Invalid IP\n"); return; } + } + if(idx!=3){ cli_write("Invalid IP\n"); return; } + ip.bytes[3]=(uint8_t)val; + int port=0; int k=0; while(portstr[k]){ char ch=portstr[k++]; if(ch<'0'||ch>'9'){ cli_write("Invalid port\n"); return; } port=port*10+(ch-'0'); } + if(port<=0||port>65535){ cli_write("Invalid port\n"); return; } + int len=(int)cli_strlen(datastr); + if(len<=0){ cli_write("No data\n"); return; } + int r=udp_send_packet(&ip,(uint16_t)port,12345,datastr,(size_t)len); + if(r==0) cli_write("Sent\n"); else cli_write("Send failed\n"); +} + +static void udp_print_callback(const ipv4_address_t* src_ip,uint16_t src_port,const mac_address_t* src_mac,const void* data,size_t length){ + (void)src_mac; + cli_write("UDP from "); + for(int i=0;i<4;i++){ cli_write_int(src_ip->bytes[i]); if(i<3) cli_write("."); } + cli_write(":"); cli_write_int(src_port); cli_write(" "); + for(size_t i=0;i65535){ cli_write("Invalid port\n"); return; } + if(udp_register_callback((uint16_t)port,udp_print_callback)==0) cli_write("UDP callback registered\n"); else cli_write("Register failed\n"); +} diff --git a/src/kernel/cli_apps/pci_list.c b/src/kernel/cli_apps/pci_list.c new file mode 100644 index 0000000..783f42d --- /dev/null +++ b/src/kernel/cli_apps/pci_list.c @@ -0,0 +1,44 @@ +#include "cli_utils.h" +#include "pci.h" + +static void print_hex16(uint16_t v){ + char buf[7]; buf[0]='0'; buf[1]='x'; + for(int i=0;i<4;i++){ + int nyb=(v >> ((3-i)*4)) & 0xF; + buf[2+i]= nyb<10?('0'+nyb):('A'+(nyb-10)); + } + buf[6]=0; + cli_write(buf); +} + +static void print_hex8(uint8_t v){ + char buf[5]; buf[0]='0'; buf[1]='x'; + int hi=(v>>4)&0xF, lo=v&0xF; + buf[2]= hi<10?('0'+hi):('A'+(hi-10)); + buf[3]= lo<10?('0'+lo):('A'+(lo-10)); + buf[4]=0; + cli_write(buf); +} + +void cli_cmd_pcilist(char *args){ + (void)args; + pci_device_t devs[64]; + int n=pci_enumerate_devices(devs,64); + cli_write("PCI devices:\n"); + for(int i=0;i #include #include +#include "network.h" #define CMD_COLS 116 #define CMD_ROWS 41 @@ -112,6 +113,9 @@ int boot_time_init = 0; // Output redirection state static FAT32_FileHandle *redirect_file = NULL; static char redirect_mode = 0; // '>' for write, 'a' for append, 0 for normal output +static bool pipe_capture_mode = false; +static char pipe_buffer[8192]; +static int pipe_buffer_pos = 0; int boot_year, boot_month, boot_day, boot_hour, boot_min, boot_sec; // --- Helpers --- @@ -197,6 +201,14 @@ static void cmd_scroll_up() { // Public for CLI apps to use void cmd_putchar(char c) { + // If pipe capture mode is enabled, write to pipe buffer + if (pipe_capture_mode) { + if (pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) { + pipe_buffer[pipe_buffer_pos++] = c; + } + return; + } + // If output is being redirected to a file, write there instead if (redirect_file && redirect_mode) { fat32_write(redirect_file, &c, 1); @@ -235,6 +247,14 @@ void cmd_putchar(char c) { // Public for CLI apps to use void cmd_write(const char *str) { + // If pipe capture mode is enabled, write to pipe buffer + if (pipe_capture_mode) { + while (*str && pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) { + pipe_buffer[pipe_buffer_pos++] = *str++; + } + return; + } + // If output is being redirected to a file, write there instead if (redirect_file && redirect_mode) { fat32_write(redirect_file, (void *)str, cmd_strlen(str)); @@ -402,19 +422,33 @@ static const CommandEntry commands[] = { {"memvalid", cli_cmd_memvalid}, {"MEMTEST", cli_cmd_memtest}, {"memtest", cli_cmd_memtest}, + // Network Commands + {"NETINIT", cli_cmd_netinit}, + {"netinit", cli_cmd_netinit}, + {"NETINFO", cli_cmd_netinfo}, + {"netinfo", cli_cmd_netinfo}, + {"IPSET", cli_cmd_ipset}, + {"ipset", cli_cmd_ipset}, + {"UDPSEND", cli_cmd_udpsend}, + {"udpsend", cli_cmd_udpsend}, + {"UDPTEST", cli_cmd_udptest}, + {"udptest", cli_cmd_udptest}, + {"PCILIST", cli_cmd_pcilist}, + {"pcilist", cli_cmd_pcilist}, {NULL, NULL} }; // --- Dispatcher --- -// Buffer for capturing command output -static char pipe_buffer[8192]; -static int pipe_buffer_pos = 0; - -static void pipe_capture_write(const char *str) { - while (*str && pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) { - pipe_buffer[pipe_buffer_pos++] = *str++; +// Find pipe operator in command string (||) +static const char* find_pipe(const char* cmd) { + while (*cmd) { + if (*cmd == '|' && *(cmd + 1) == '|') { + return cmd; + } + cmd++; } + return NULL; } // Execute a single command @@ -445,6 +479,160 @@ static void cmd_exec_single(char *cmd) { // Execute command with redirection and pipe support static void cmd_exec(char *cmd) { + // Check for pipe operator first + const char* pipe_pos = find_pipe(cmd); + if (pipe_pos) { + // Handle piped commands + char left_cmd[256] = {0}; + char right_cmd[256] = {0}; + + // Extract left command (before pipe) + size_t left_len = pipe_pos - cmd; + if (left_len >= sizeof(left_cmd)) left_len = sizeof(left_cmd) - 1; + for (size_t j = 0; j < left_len; j++) { + left_cmd[j] = cmd[j]; + } + left_cmd[left_len] = '\0'; + + // Trim trailing spaces from left command + while (left_len > 0 && left_cmd[left_len - 1] == ' ') { + left_cmd[--left_len] = '\0'; + } + + // Extract right command (after pipe ||) + const char* right_start = pipe_pos + 2; // Skip both '|' characters + while (*right_start == ' ') right_start++; + + size_t right_len = 0; + while (right_start[right_len] && right_len < sizeof(right_cmd) - 1) { + right_cmd[right_len] = right_start[right_len]; + right_len++; + } + right_cmd[right_len] = '\0'; + + // Trim trailing spaces from right command + while (right_len > 0 && right_cmd[right_len - 1] == ' ') { + right_cmd[--right_len] = '\0'; + } + + // Check if right command is UDPSEND + char right_upper[256] = {0}; + for (int i = 0; right_cmd[i] && i < 255; i++) { + right_upper[i] = right_cmd[i] >= 'a' && right_cmd[i] <= 'z' + ? right_cmd[i] - 32 + : right_cmd[i]; + } + + if (right_upper[0] == 'U' && right_upper[1] == 'D' && right_upper[2] == 'P' && + right_upper[3] == 'S' && right_upper[4] == 'E' && right_upper[5] == 'N' && + right_upper[6] == 'D' && (right_upper[7] == ' ' || right_upper[7] == '\0')) { + + // Parse UDPSEND arguments (IP and PORT only) + const char* args = right_cmd + 7; + while (*args == ' ') args++; + + if (!network_is_initialized()) { + cmd_write("Error: Network not initialized. Use NETINIT first.\n"); + return; + } + + // Parse IP address + ipv4_address_t dest_ip; + int ip_bytes[4] = {0}; + int ip_idx = 0; + int current = 0; + const char* p = args; + + // Parse IP + while (*p && ip_idx < 4) { + if (*p >= '0' && *p <= '9') { + current = current * 10 + (*p - '0'); + } else if (*p == '.' || *p == ' ') { + ip_bytes[ip_idx++] = current; + current = 0; + if (*p == ' ') break; + } + p++; + } + if (ip_idx < 4 && current > 0) { + ip_bytes[ip_idx++] = current; + } + + if (ip_idx < 4) { + cmd_write("Error: Invalid IP address\n"); + return; + } + + for (int k = 0; k < 4; k++) { + dest_ip.bytes[k] = (uint8_t)ip_bytes[k]; + } + + // Parse port + while (*p == ' ') p++; + int port = 0; + while (*p >= '0' && *p <= '9') { + port = port * 10 + (*p - '0'); + p++; + } + + if (port == 0 || port > 65535) { + cmd_write("Error: Invalid port number\n"); + return; + } + + // Initialize pipe buffer + pipe_buffer_pos = 0; + pipe_capture_mode = true; + + // Execute the left command and capture its output + cmd_exec_single(left_cmd); + + // Disable pipe capture mode + pipe_capture_mode = false; + + // Null-terminate the captured output + pipe_buffer[pipe_buffer_pos] = '\0'; + + if (pipe_buffer_pos == 0) { + cmd_write("Error: No output to send\n"); + return; + } + + // Send UDP packet(s) with captured output (chunked if necessary) + const size_t chunk_size = 512; + size_t offset = 0; + int sent_bytes = 0; + + while (offset < (size_t)pipe_buffer_pos) { + size_t to_send = pipe_buffer_pos - offset; + if (to_send > chunk_size) { + to_send = chunk_size; + } + + // Send directly from pipe buffer + int result = udp_send_packet(&dest_ip, (uint16_t)port, 54321, + (const void*)(pipe_buffer + offset), to_send); + if (result == 0) { + sent_bytes += to_send; + } + offset += to_send; + } + + if (sent_bytes > 0) { + cmd_write("UDP packets sent successfully ("); + cmd_write_int(sent_bytes); + cmd_write(" bytes)\n"); + } else { + cmd_write("Error: Failed to send UDP packets\n"); + } + + return; + } else { + cmd_write("Error: Only UDPSEND is supported after pipe operator\n"); + return; + } + } + // Check for redirection operators (> or >>) char *redirect_ptr = NULL; char redirect_op = 0; // '>' or 'a' for append diff --git a/src/kernel/e1000.c b/src/kernel/e1000.c new file mode 100644 index 0000000..3f2d7ea --- /dev/null +++ b/src/kernel/e1000.c @@ -0,0 +1,145 @@ +#include +#include +#include "e1000.h" +#include "pci.h" +#include "io.h" +#include "platform.h" + +static e1000_device_t e1000_dev; +static int e1000_initialized = 0; +static e1000_tx_desc_t tx_descriptors[E1000_TX_RING_SIZE] __attribute__((aligned(16))); +static e1000_rx_desc_t rx_descriptors[E1000_RX_RING_SIZE] __attribute__((aligned(16))); +static uint8_t tx_buffers[E1000_TX_RING_SIZE][2048] __attribute__((aligned(16))); +static uint8_t rx_buffers[E1000_RX_RING_SIZE][2048] __attribute__((aligned(16))); + +static void* kmemcpy(void* dest, const void* src, size_t n) { + uint8_t* d = (uint8_t*)dest; + const uint8_t* s = (const uint8_t*)src; + for (size_t i = 0; i < n; i++) d[i] = s[i]; + return dest; +} + +int e1000_init(pci_device_t* pci_dev) { + if (e1000_initialized) return 0; + uint32_t bar0 = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x10); + if (bar0 == 0 || bar0 == 0xFFFFFFFF) return -1; + if (bar0 & 1) return -1; + uint64_t mmio_base_phys = (uint64_t)(bar0 & ~0xF); + volatile uint32_t* mmio_base = (volatile uint32_t*)(uintptr_t)p2v(mmio_base_phys); + e1000_dev.mmio_base = mmio_base; + e1000_dev.pci_dev = *pci_dev; + e1000_dev.initialized = 0; + + uint32_t command = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x04); + command |= (1 << 2); + command |= (1 << 1); + pci_write_config(pci_dev->bus, pci_dev->device, pci_dev->function, 0x04, command); + + uint32_t status = e1000_read_reg(mmio_base, E1000_REG_STATUS); + (void)status; + uint32_t ctrl = e1000_read_reg(mmio_base, E1000_REG_CTRL); + e1000_write_reg(mmio_base, E1000_REG_CTRL, ctrl | E1000_CTRL_RST); + for (int i = 0; i < 100000; i++) { + ctrl = e1000_read_reg(mmio_base, E1000_REG_CTRL); + if (!(ctrl & E1000_CTRL_RST)) break; + } + + uint32_t ral = e1000_read_reg(mmio_base, E1000_REG_RAL); + uint32_t rah = e1000_read_reg(mmio_base, E1000_REG_RAH); + e1000_dev.mac_address.bytes[0] = (uint8_t)(ral & 0xFF); + e1000_dev.mac_address.bytes[1] = (uint8_t)((ral >> 8) & 0xFF); + e1000_dev.mac_address.bytes[2] = (uint8_t)((ral >> 16) & 0xFF); + e1000_dev.mac_address.bytes[3] = (uint8_t)((ral >> 24) & 0xFF); + e1000_dev.mac_address.bytes[4] = (uint8_t)(rah & 0xFF); + e1000_dev.mac_address.bytes[5] = (uint8_t)((rah >> 8) & 0xFF); + + e1000_dev.tx_descriptors = tx_descriptors; + e1000_dev.tx_head = 0; + e1000_dev.tx_tail = 0; + for (int i = 0; i < E1000_TX_RING_SIZE; i++) { + e1000_dev.tx_buffers[i] = tx_buffers[i]; + e1000_dev.tx_descriptors[i].buffer_addr = v2p((uint64_t)(uintptr_t)tx_buffers[i]); + e1000_dev.tx_descriptors[i].length = 0; + e1000_dev.tx_descriptors[i].cso = 0; + e1000_dev.tx_descriptors[i].cmd = 0; + e1000_dev.tx_descriptors[i].status = 0; + e1000_dev.tx_descriptors[i].css = 0; + e1000_dev.tx_descriptors[i].special = 0; + } + uint64_t tx_desc_phys = v2p((uint64_t)(uintptr_t)tx_descriptors); + e1000_write_reg(mmio_base, E1000_REG_TDBAL, (uint32_t)(tx_desc_phys & 0xFFFFFFFF)); + e1000_write_reg(mmio_base, E1000_REG_TDBAH, (uint32_t)(tx_desc_phys >> 32)); + e1000_write_reg(mmio_base, E1000_REG_TDLEN, E1000_TX_RING_SIZE * sizeof(e1000_tx_desc_t)); + e1000_write_reg(mmio_base, E1000_REG_TDH, 0); + e1000_write_reg(mmio_base, E1000_REG_TDT, 0); + uint32_t tctl = E1000_TCTL_EN | E1000_TCTL_PSP | (E1000_TCTL_CT & (0x10 << 4)) | (E1000_TCTL_COLD & (0x40 << 12)); + e1000_write_reg(mmio_base, E1000_REG_TCTL, tctl); + e1000_write_reg(mmio_base, E1000_REG_TIPG, 0x0060200A); + + e1000_dev.rx_descriptors = rx_descriptors; + e1000_dev.rx_head = 0; + e1000_dev.rx_tail = E1000_RX_RING_SIZE - 1; + for (int i = 0; i < E1000_RX_RING_SIZE; i++) { + e1000_dev.rx_buffers[i] = rx_buffers[i]; + e1000_dev.rx_descriptors[i].buffer_addr = v2p((uint64_t)(uintptr_t)rx_buffers[i]); + e1000_dev.rx_descriptors[i].length = 0; + e1000_dev.rx_descriptors[i].checksum = 0; + e1000_dev.rx_descriptors[i].status = 0; + e1000_dev.rx_descriptors[i].errors = 0; + e1000_dev.rx_descriptors[i].special = 0; + } + uint64_t rx_desc_phys = v2p((uint64_t)(uintptr_t)rx_descriptors); + e1000_write_reg(mmio_base, E1000_REG_RDBAL, (uint32_t)(rx_desc_phys & 0xFFFFFFFF)); + e1000_write_reg(mmio_base, E1000_REG_RDBAH, (uint32_t)(rx_desc_phys >> 32)); + e1000_write_reg(mmio_base, E1000_REG_RDLEN, E1000_RX_RING_SIZE * sizeof(e1000_rx_desc_t)); + e1000_write_reg(mmio_base, E1000_REG_RDH, 0); + e1000_write_reg(mmio_base, E1000_REG_RDT, E1000_RX_RING_SIZE - 1); + uint32_t rctl = E1000_RCTL_EN | E1000_RCTL_SBP | E1000_RCTL_UPE | E1000_RCTL_MPE | + E1000_RCTL_LPE | E1000_RCTL_LBM_NONE | E1000_RCTL_RDMTS_HALF | + E1000_RCTL_MO_36 | E1000_RCTL_BAM | E1000_RCTL_BSIZE_2048 | E1000_RCTL_SECRC; + e1000_write_reg(mmio_base, E1000_REG_RCTL, rctl); + ctrl = e1000_read_reg(mmio_base, E1000_REG_CTRL); + e1000_write_reg(mmio_base, E1000_REG_CTRL, ctrl | E1000_CTRL_SLU); + e1000_dev.initialized = 1; + e1000_initialized = 1; + return 0; +} + +e1000_device_t* e1000_get_device(void) { + if (!e1000_initialized) return NULL; + return &e1000_dev; +} + +int e1000_send_packet(const void* data, size_t length) { + if (!e1000_initialized || !e1000_dev.initialized) return -1; + if (length > 2048) return -1; + volatile uint32_t* mmio = e1000_dev.mmio_base; + uint16_t next_tail = (e1000_dev.tx_tail + 1) % E1000_TX_RING_SIZE; + if (next_tail == e1000_dev.tx_head) return -1; + kmemcpy(e1000_dev.tx_buffers[e1000_dev.tx_tail], data, length); + e1000_dev.tx_descriptors[e1000_dev.tx_tail].length = (uint16_t)length; + e1000_dev.tx_descriptors[e1000_dev.tx_tail].cmd = 0x0B; + e1000_dev.tx_descriptors[e1000_dev.tx_tail].status = 0; + e1000_dev.tx_tail = next_tail; + e1000_write_reg(mmio, E1000_REG_TDT, e1000_dev.tx_tail); + return 0; +} + +int e1000_receive_packet(void* buffer, size_t buffer_size) { + if (!e1000_initialized || !e1000_dev.initialized) return 0; + volatile uint32_t* mmio = e1000_dev.mmio_base; + uint16_t hw_head = e1000_read_reg(mmio, E1000_REG_RDH); + uint16_t tail = e1000_read_reg(mmio, E1000_REG_RDT); + uint16_t next_idx = (tail + 1) % E1000_RX_RING_SIZE; + if (hw_head == next_idx) return 0; + if (!(e1000_dev.rx_descriptors[next_idx].status & 1)) return 0; + uint16_t length = e1000_dev.rx_descriptors[next_idx].length - 4; + if (length > buffer_size) length = (uint16_t)buffer_size; + kmemcpy(buffer, e1000_dev.rx_buffers[next_idx], length); + e1000_dev.rx_descriptors[next_idx].status = 0; + e1000_dev.rx_descriptors[next_idx].length = 0; + tail = next_idx; + e1000_write_reg(mmio, E1000_REG_RDT, tail); + e1000_dev.rx_tail = tail; + return (int)length; +} diff --git a/src/kernel/e1000.h b/src/kernel/e1000.h new file mode 100644 index 0000000..7d93441 --- /dev/null +++ b/src/kernel/e1000.h @@ -0,0 +1,99 @@ +#ifndef E1000_H +#define E1000_H + +#include +#include +#include "pci.h" + +#define E1000_VENDOR_ID 0x8086 +#define E1000_DEVICE_ID_82540EM 0x100E + +#define E1000_REG_CTRL 0x0000 +#define E1000_REG_STATUS 0x0008 +#define E1000_REG_EERD 0x0014 +#define E1000_REG_ICR 0x00C0 +#define E1000_REG_IMS 0x00D0 +#define E1000_REG_RCTL 0x0100 +#define E1000_REG_TCTL 0x0400 +#define E1000_REG_TIPG 0x0410 +#define E1000_REG_RDBAL 0x2800 +#define E1000_REG_RDBAH 0x2804 +#define E1000_REG_RDLEN 0x2808 +#define E1000_REG_RDH 0x2810 +#define E1000_REG_RDT 0x2818 +#define E1000_REG_TDBAL 0x3800 +#define E1000_REG_TDBAH 0x3804 +#define E1000_REG_TDLEN 0x3808 +#define E1000_REG_TDH 0x3810 +#define E1000_REG_TDT 0x3818 +#define E1000_REG_RAL 0x5400 +#define E1000_REG_RAH 0x5404 + +#define E1000_CTRL_RST (1 << 26) +#define E1000_CTRL_SLU (1 << 6) + +#define E1000_RCTL_EN (1 << 1) +#define E1000_RCTL_SBP (1 << 2) +#define E1000_RCTL_UPE (1 << 3) +#define E1000_RCTL_MPE (1 << 4) +#define E1000_RCTL_LPE (1 << 5) +#define E1000_RCTL_LBM_NONE (0 << 6) +#define E1000_RCTL_RDMTS_HALF (0 << 8) +#define E1000_RCTL_MO_36 (0 << 12) +#define E1000_RCTL_BAM (1 << 15) +#define E1000_RCTL_BSIZE_2048 (1 << 16) +#define E1000_RCTL_SECRC (1 << 26) + +#define E1000_TCTL_EN (1 << 1) +#define E1000_TCTL_PSP (1 << 3) +#define E1000_TCTL_CT (0xF << 4) +#define E1000_TCTL_COLD (0x3F << 12) + +#define E1000_ICR_TXDW (1 << 0) +#define E1000_ICR_RXT0 (1 << 7) + +#define E1000_TX_RING_SIZE 32 +#define E1000_RX_RING_SIZE 32 + +typedef struct { + uint64_t buffer_addr; + uint16_t length; + uint8_t cso; + uint8_t cmd; + uint8_t status; + uint8_t css; + uint16_t special; +} __attribute__((packed)) e1000_tx_desc_t; + +typedef struct { + uint64_t buffer_addr; + uint16_t length; + uint16_t checksum; + uint8_t status; + uint8_t errors; + uint16_t special; +} __attribute__((packed)) e1000_rx_desc_t; + +typedef struct { + volatile uint32_t* mmio_base; + pci_device_t pci_dev; + int initialized; + struct { uint8_t bytes[6]; } mac_address; + e1000_tx_desc_t* tx_descriptors; + void* tx_buffers[E1000_TX_RING_SIZE]; + uint16_t tx_head; + uint16_t tx_tail; + e1000_rx_desc_t* rx_descriptors; + void* rx_buffers[E1000_RX_RING_SIZE]; + uint16_t rx_head; + uint16_t rx_tail; +} e1000_device_t; + +int e1000_init(pci_device_t* pci_dev); +static inline uint32_t e1000_read_reg(volatile uint32_t* mmio_base, uint16_t offset) { return mmio_base[offset / 4]; } +static inline void e1000_write_reg(volatile uint32_t* mmio_base, uint16_t offset, uint32_t value) { mmio_base[offset / 4] = value; } +e1000_device_t* e1000_get_device(void); +int e1000_send_packet(const void* data, size_t length); +int e1000_receive_packet(void* buffer, size_t buffer_size); + +#endif diff --git a/src/kernel/io.h b/src/kernel/io.h index 98edf6e..2fa04d3 100644 --- a/src/kernel/io.h +++ b/src/kernel/io.h @@ -17,6 +17,16 @@ static inline uint8_t inb(uint16_t port) { return ret; } +static inline void outl(uint16_t port, uint32_t val) { + asm volatile ("outl %0, %1" : : "a"(val), "Nd"(port)); +} + +static inline uint32_t inl(uint16_t port) { + uint32_t ret; + asm volatile ("inl %1, %0" : "=a"(ret) : "Nd"(port)); + return ret; +} + static inline void io_wait(void) { outb(0x80, 0); } diff --git a/src/kernel/main.c b/src/kernel/main.c index fa57df5..902ac19 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -8,6 +8,7 @@ #include "wm.h" #include "io.h" #include "memory_manager.h" +#include "platform.h" // --- Limine Requests --- __attribute__((used, section(".requests"))) @@ -46,6 +47,7 @@ static void hcf(void) { // Kernel Entry Point void kmain(void) { + platform_init(); // 1. Graphics Init if (LIMINE_BASE_REVISION_SUPPORTED == false) { // Warning @@ -103,4 +105,4 @@ void kmain(void) { while (1) { asm("hlt"); } -} \ No newline at end of file +} diff --git a/src/kernel/network.c b/src/kernel/network.c new file mode 100644 index 0000000..c9a779d --- /dev/null +++ b/src/kernel/network.c @@ -0,0 +1,433 @@ +#include +#include +#include "network.h" +#include "e1000.h" +#include "pci.h" + +static int network_initialized = 0; +static mac_address_t our_mac; +static ipv4_address_t our_ip = {{0,0,0,0}}; +static uint16_t ipv4_id_counter = 0; + +typedef struct { ipv4_address_t ip; mac_address_t mac; uint32_t timestamp; int valid; } arp_cache_entry_t; +#define ARP_CACHE_SIZE 16 +static arp_cache_entry_t arp_cache[ARP_CACHE_SIZE]; +static int arp_cache_initialized = 0; + +#define UDP_MAX_CALLBACKS 8 +typedef struct { uint16_t port; udp_callback_t callback; int valid; } udp_callback_entry_t; +static udp_callback_entry_t udp_callbacks[UDP_MAX_CALLBACKS]; + +static int frames_received_count = 0; +static int udp_packets_received_count = 0; +static int udp_callbacks_called_count = 0; +static int e1000_receive_calls = 0; +static int e1000_receive_empty = 0; +static int network_process_calls = 0; + +static void* kmemcpy(void* d, const void* s, size_t n){uint8_t*D=d;const uint8_t*S=s;for(size_t i=0;i>8)&0xFF));} +static uint16_t ntohs(uint16_t x){return htons(x);} +static uint32_t htonl(uint32_t v){return ((v&0xFF)<<24)|((v&0xFF00)<<8)|((v>>8)&0xFF00)|((v>>24)&0xFF);} + +static uint16_t ipv4_checksum(const ipv4_header_t* h){ + uint32_t sum=0;const uint16_t* w=(const uint16_t*)h; + for(int i=0;i<10;i++) sum+=w[i]; + while(sum>>16) sum=(sum&0xFFFF)+(sum>>16); + return (uint16_t)(~sum); +} + +static void arp_cache_init(void){ if(arp_cache_initialized) return; kmemset(arp_cache,0,sizeof(arp_cache)); arp_cache_initialized=1; } +static arp_cache_entry_t* arp_cache_find(const ipv4_address_t* ip){ for(int i=0;imac,mac,sizeof(mac_address_t)); e->timestamp=0; return;} for(int i=0;imac_address; + return 0; +} + +int network_get_ipv4_address(ipv4_address_t* ip){ if(!network_initialized) return -1; *ip=our_ip; return 0; } +int network_set_ipv4_address(const ipv4_address_t* ip){ if(!network_initialized) return -1; our_ip=*ip; return 0; } + +int network_send_frame(const void* data,size_t length){ if(!network_initialized) return -1; if(length>ETH_FRAME_MAX_SIZE) return -1; return e1000_send_packet(data,length); } + +int network_receive_frame(void* buffer,size_t buffer_size){ + if(!network_initialized) return 0; + e1000_receive_calls++; + int result=e1000_receive_packet(buffer,buffer_size); + if(result==0) e1000_receive_empty++; + return result; +} + +void network_process_frames(void){ + network_process_calls++; + if(!network_initialized) return; + uint8_t frame_buffer[ETH_FRAME_MAX_SIZE]; + int frame_length; + while((frame_length=network_receive_frame(frame_buffer,sizeof(frame_buffer)))>0){ + frames_received_count++; + if(frame_length<(int)sizeof(eth_header_t)) continue; + eth_header_t* eth=(eth_header_t*)frame_buffer; + uint16_t ethertype=ntohs(eth->ethertype); + int is_broadcast=1; int is_for_us=1; + for(int i=0;i<6;i++){ if(eth->dest_mac[i]!=0xFF) is_broadcast=0; if(eth->dest_mac[i]!=our_mac.bytes[i]) is_for_us=0; } + if(!is_broadcast && !is_for_us) continue; + void* payload=frame_buffer+sizeof(eth_header_t); + size_t payload_length=frame_length-sizeof(eth_header_t); + if(ethertype==ETH_ETHERTYPE_ARP){ + if(payload_length>=sizeof(arp_header_t)) arp_process_packet((arp_header_t*)payload,payload_length); + } else if(ethertype==ETH_ETHERTYPE_IPV4){ + if(payload_length>=sizeof(ipv4_header_t)){ + ipv4_header_t* ip=(ipv4_header_t*)payload; + uint16_t checksum=ip->checksum; + ip->checksum=0; + uint16_t calc=ipv4_checksum(ip); + ip->checksum=checksum; + if(checksum==calc){ + int for_our_ip=1; + for(int i=0;i<4;i++){ if(ip->dest_ip[i]!=our_ip.bytes[i]) { for_our_ip=0; break; } } + if(for_our_ip || ip->dest_ip[0]==255){ + mac_address_t src_mac; + kmemcpy(src_mac.bytes,eth->src_mac,6); + ipv4_process_packet(ip,&src_mac,payload_length); + } + } + } + } + } +} + +int arp_send_request(const ipv4_address_t* target_ip){ + if(!network_initialized) return -1; + uint8_t frame[ETH_FRAME_MAX_SIZE]; + eth_header_t* eth=(eth_header_t*)frame; + arp_header_t* arp=(arp_header_t*)(frame+sizeof(eth_header_t)); + for(int i=0;i<6;i++) eth->dest_mac[i]=0xFF; + kmemcpy(eth->src_mac,our_mac.bytes,6); + eth->ethertype=htons(ETH_ETHERTYPE_ARP); + arp->hw_type=htons(1); + arp->proto_type=htons(ETH_ETHERTYPE_IPV4); + arp->hw_len=6; + arp->proto_len=4; + arp->opcode=htons(ARP_OP_REQUEST); + kmemcpy(arp->sender_mac,our_mac.bytes,6); + kmemcpy(arp->sender_ip,our_ip.bytes,4); + for(int i=0;i<6;i++) arp->target_mac[i]=0; + kmemcpy(arp->target_ip,target_ip->bytes,4); + size_t frame_length=sizeof(eth_header_t)+sizeof(arp_header_t); + return network_send_frame(frame,frame_length); +} + +int arp_lookup(const ipv4_address_t* ip,mac_address_t* mac){ + if(!network_initialized) return -1; + arp_cache_entry_t* e=arp_cache_find(ip); + if(e && e->valid){ *mac=e->mac; return 0; } + arp_send_request(ip); + return -1; +} + +void arp_process_packet(const arp_header_t* arp,size_t length){ + if(lengthhw_type)!=1 || ntohs(arp->proto_type)!=ETH_ETHERTYPE_IPV4) return; + uint16_t opcode=ntohs(arp->opcode); + ipv4_address_t sender_ip; mac_address_t sender_mac; + kmemcpy(sender_ip.bytes,arp->sender_ip,4); + kmemcpy(sender_mac.bytes,arp->sender_mac,6); + arp_cache_add(&sender_ip,&sender_mac); + if(opcode==ARP_OP_REQUEST){ + int is_for_us=1; + for(int i=0;i<4;i++){ if(arp->target_ip[i]!=our_ip.bytes[i]) { is_for_us=0; break; } } + if(is_for_us){ + uint8_t frame[ETH_FRAME_MAX_SIZE]; + eth_header_t* eth=(eth_header_t*)frame; + arp_header_t* r=(arp_header_t*)(frame+sizeof(eth_header_t)); + kmemcpy(eth->dest_mac,arp->sender_mac,6); + kmemcpy(eth->src_mac,our_mac.bytes,6); + eth->ethertype=htons(ETH_ETHERTYPE_ARP); + r->hw_type=htons(1); + r->proto_type=htons(ETH_ETHERTYPE_IPV4); + r->hw_len=6; + r->proto_len=4; + r->opcode=htons(ARP_OP_REPLY); + kmemcpy(r->sender_mac,our_mac.bytes,6); + kmemcpy(r->sender_ip,our_ip.bytes,4); + kmemcpy(r->target_mac,arp->sender_mac,6); + kmemcpy(r->target_ip,arp->sender_ip,4); + size_t frame_length=sizeof(eth_header_t)+sizeof(arp_header_t); + network_send_frame(frame,frame_length); + } + } +} + +int ipv4_send_packet(const ipv4_address_t* dest_ip,uint8_t protocol,const void* data,size_t data_length){ + if(!network_initialized) return -1; + mac_address_t dest_mac; + int is_bcast=(dest_ip->bytes[0]==255 && dest_ip->bytes[1]==255 && dest_ip->bytes[2]==255 && dest_ip->bytes[3]==255); + if(is_bcast){ for(int i=0;i<6;i++) dest_mac.bytes[i]=0xFF; } + else { int ok=arp_lookup(dest_ip,&dest_mac); if(ok!=0){ for(int i=0;i<6;i++) dest_mac.bytes[i]=0xFF; } } + uint8_t frame[ETH_FRAME_MAX_SIZE]; + eth_header_t* eth=(eth_header_t*)frame; + ipv4_header_t* ip=(ipv4_header_t*)(frame+sizeof(eth_header_t)); + void* ip_payload=frame+sizeof(eth_header_t)+sizeof(ipv4_header_t); + kmemcpy(eth->dest_mac,dest_mac.bytes,6); + kmemcpy(eth->src_mac,our_mac.bytes,6); + eth->ethertype=htons(ETH_ETHERTYPE_IPV4); + ip->version_ihl=(4<<4)|5; + ip->tos=0; + ip->total_length=htons(sizeof(ipv4_header_t)+data_length); + ip->id=htons(ipv4_id_counter++); + ip->flags_frag=0; + ip->ttl=64; + ip->protocol=protocol; + ip->checksum=0; + kmemcpy(ip->src_ip,our_ip.bytes,4); + kmemcpy(ip->dest_ip,dest_ip->bytes,4); + ip->checksum=ipv4_checksum(ip); + kmemcpy(ip_payload,data,data_length); + size_t frame_length=sizeof(eth_header_t)+sizeof(ipv4_header_t)+data_length; + return network_send_frame(frame,frame_length); +} + +int ipv4_send_packet_to_mac(const ipv4_address_t* dest_ip,const mac_address_t* dest_mac,uint8_t protocol,const void* data,size_t data_length){ + if(!network_initialized) return -1; + uint8_t frame[ETH_FRAME_MAX_SIZE]; + eth_header_t* eth=(eth_header_t*)frame; + ipv4_header_t* ip=(ipv4_header_t*)(frame+sizeof(eth_header_t)); + void* ip_payload=frame+sizeof(eth_header_t)+sizeof(ipv4_header_t); + kmemcpy(eth->dest_mac,dest_mac->bytes,6); + kmemcpy(eth->src_mac,our_mac.bytes,6); + eth->ethertype=htons(ETH_ETHERTYPE_IPV4); + ip->version_ihl=(4<<4)|5; + ip->tos=0; + ip->total_length=htons(sizeof(ipv4_header_t)+data_length); + ip->id=htons(ipv4_id_counter++); + ip->flags_frag=0; + ip->ttl=64; + ip->protocol=protocol; + ip->checksum=0; + kmemcpy(ip->src_ip,our_ip.bytes,4); + kmemcpy(ip->dest_ip,dest_ip->bytes,4); + ip->checksum=ipv4_checksum(ip); + kmemcpy(ip_payload,data,data_length); + size_t frame_length=sizeof(eth_header_t)+sizeof(ipv4_header_t)+data_length; + return network_send_frame(frame,frame_length); +} + +void ipv4_process_packet(const ipv4_header_t* ip,const mac_address_t* src_mac,size_t length){ + if(lengthversion_ihl & 0x0F)*4; + if(ihl<20 || lengthtotal_length); + if(total_length>length) return; + void* payload=(void*)ip+ihl; + size_t payload_length=total_length-ihl; + if(ip->protocol==IP_PROTO_UDP){ + if(payload_length>=sizeof(udp_header_t)){ + udp_packets_received_count++; + ipv4_address_t src_ip; + kmemcpy(src_ip.bytes,ip->src_ip,4); + udp_header_t* udp=(udp_header_t*)payload; + uint16_t dest_port=ntohs(udp->dest_port); + uint16_t src_port=ntohs(udp->src_port); + uint16_t udp_length=ntohs(udp->length); + if(udp_length>payload_length) return; + void* udp_payload=(void*)udp+sizeof(udp_header_t); + size_t udp_payload_length=udp_length-sizeof(udp_header_t); + for(int i=0;isrc_port=htons(src_port); + udp->dest_port=htons(dest_port); + udp->length=htons(sizeof(udp_header_t)+data_length); + udp->checksum=0; + kmemcpy(udp_payload,data,data_length); + size_t udp_packet_length=sizeof(udp_header_t)+data_length; + return ipv4_send_packet(dest_ip,IP_PROTO_UDP,udp_packet,udp_packet_length); +} + +int udp_send_packet_to_mac(const ipv4_address_t* dest_ip,const mac_address_t* dest_mac,uint16_t dest_port,uint16_t src_port,const void* data,size_t data_length){ + if(!network_initialized) return -1; + uint8_t udp_packet[ETH_FRAME_MAX_SIZE]; + udp_header_t* udp=(udp_header_t*)udp_packet; + void* udp_payload=udp_packet+sizeof(udp_header_t); + udp->src_port=htons(src_port); + udp->dest_port=htons(dest_port); + udp->length=htons(sizeof(udp_header_t)+data_length); + udp->checksum=0; + kmemcpy(udp_payload,data,data_length); + size_t udp_packet_length=sizeof(udp_header_t)+data_length; + return ipv4_send_packet_to_mac(dest_ip,dest_mac,IP_PROTO_UDP,udp_packet,udp_packet_length); +} + +int udp_register_callback(uint16_t port,udp_callback_t callback){ + if(!network_initialized) return -1; + for(int i=0;i>8)&0xFF00)|((v>>24)&0xFF);} +static uint32_t ntohl32(uint32_t v){return htonl32(v);} +static uint16_t htons16(uint16_t v){return (uint16_t)(((v&0xFF)<<8)|((v>>8)&0xFF));} + +static void dhcp_build_discover(dhcp_packet_t* pkt){ + kmemset(pkt,0,sizeof(dhcp_packet_t)); + pkt->op=DHCP_OP_BOOTREQUEST; pkt->htype=DHCP_HTYPE_ETHERNET; pkt->hlen=DHCP_HLEN_ETHERNET; pkt->xid=htonl32(dhcp_xid); pkt->flags=htons16(0x8000); + kmemcpy(pkt->chaddr,our_mac.bytes,6); + pkt->magic_cookie=htonl32(DHCP_MAGIC_COOKIE); + uint8_t* opt=pkt->options; + *opt++=DHCP_OPT_MSG_TYPE; *opt++=1; *opt++=DHCP_MSG_DISCOVER; + *opt++=DHCP_OPT_PARAM_REQ_LIST; *opt++=3; *opt++=1; *opt++=3; *opt++=6; + *opt++=DHCP_OPT_END; +} + +static void dhcp_build_request(dhcp_packet_t* pkt){ + kmemset(pkt,0,sizeof(dhcp_packet_t)); + pkt->op=DHCP_OP_BOOTREQUEST; pkt->htype=DHCP_HTYPE_ETHERNET; pkt->hlen=DHCP_HLEN_ETHERNET; pkt->xid=htonl32(dhcp_xid); pkt->flags=htons16(0x8000); + kmemcpy(pkt->chaddr,our_mac.bytes,6); + pkt->magic_cookie=htonl32(DHCP_MAGIC_COOKIE); + uint8_t* opt=pkt->options; + *opt++=DHCP_OPT_MSG_TYPE; *opt++=1; *opt++=DHCP_MSG_REQUEST; + *opt++=DHCP_OPT_REQ_IP; *opt++=4; *opt++=dhcp_offered_ip.bytes[0]; *opt++=dhcp_offered_ip.bytes[1]; *opt++=dhcp_offered_ip.bytes[2]; *opt++=dhcp_offered_ip.bytes[3]; + *opt++=DHCP_OPT_SERVER_ID; *opt++=4; + *opt++=(uint8_t)((dhcp_server_id>>24)&0xFF); *opt++=(uint8_t)((dhcp_server_id>>16)&0xFF); *opt++=(uint8_t)((dhcp_server_id>>8)&0xFF); *opt++=(uint8_t)(dhcp_server_id&0xFF); + *opt++=DHCP_OPT_END; +} + +static uint8_t dhcp_get_option(const uint8_t* opts,uint8_t code){ + const uint8_t* p=opts; + while(*p!=DHCP_OPT_END){ uint8_t c=*p++; uint8_t l=*p++; if(c==code) return p[0]; p+=l; } + return 0; +} + +static void dhcp_udp_callback(const ipv4_address_t* src_ip,uint16_t src_port,const mac_address_t* src_mac,const void* payload,size_t payload_length){ + (void)src_ip; (void)src_mac; + if(src_port!=DHCP_SERVER_PORT || payload_lengthop!=DHCP_OP_BOOTREPLY) return; + if(ntohl32(pkt->xid)!=dhcp_xid) return; + if(ntohl32(pkt->magic_cookie)!=DHCP_MAGIC_COOKIE) return; + uint8_t mtype=dhcp_get_option(pkt->options,DHCP_OPT_MSG_TYPE); + if(mtype==DHCP_MSG_OFFER){ + uint32_t yi_host=ntohl32(pkt->yiaddr); + dhcp_offered_ip.bytes[0]=(uint8_t)((yi_host>>24)&0xFF); + dhcp_offered_ip.bytes[1]=(uint8_t)((yi_host>>16)&0xFF); + dhcp_offered_ip.bytes[2]=(uint8_t)((yi_host>>8)&0xFF); + dhcp_offered_ip.bytes[3]=(uint8_t)(yi_host&0xFF); + const uint8_t* p=pkt->options; dhcp_server_id=0; + while(*p!=DHCP_OPT_END){ uint8_t c=*p++; uint8_t l=*p++; if(c==DHCP_OPT_SERVER_ID && l==4){ dhcp_server_id=((uint32_t)p[0]<<24)|((uint32_t)p[1]<<16)|((uint32_t)p[2]<<8)|(uint32_t)p[3]; break; } p+=l; } + if(dhcp_server_id!=0) dhcp_state=1; + } else if(mtype==DHCP_MSG_ACK){ + uint32_t yi_host=ntohl32(pkt->yiaddr); + our_ip.bytes[0]=(uint8_t)((yi_host>>24)&0xFF); + our_ip.bytes[1]=(uint8_t)((yi_host>>16)&0xFF); + our_ip.bytes[2]=(uint8_t)((yi_host>>8)&0xFF); + our_ip.bytes[3]=(uint8_t)(yi_host&0xFF); + dhcp_state=2; + } else if(mtype==DHCP_MSG_NAK){ + dhcp_state=-1; + } +} + +int network_dhcp_acquire(void){ + if(!network_initialized) return -1; + if(udp_register_callback(DHCP_CLIENT_PORT,dhcp_udp_callback)!=0) return -1; + dhcp_xid += 0x12345u + (uint32_t)ipv4_id_counter; + dhcp_state=0; dhcp_server_id=0; + dhcp_packet_t pkt; + dhcp_build_discover(&pkt); + ipv4_address_t bcast={{255,255,255,255}}; + udp_send_packet(&bcast,DHCP_SERVER_PORT,DHCP_CLIENT_PORT,&pkt,sizeof(dhcp_packet_t)); + for(int i=0;i<500000 && dhcp_state==0;i++){ network_process_frames(); if(i%1000==0){ for(volatile int d=0; d<100000; d++){} } } + if(dhcp_state!=1) return -1; + dhcp_build_request(&pkt); + udp_send_packet(&bcast,DHCP_SERVER_PORT,DHCP_CLIENT_PORT,&pkt,sizeof(dhcp_packet_t)); + for(int i=0;i<500000 && dhcp_state==1;i++){ network_process_frames(); if(i%1000==0){ for(volatile int d=0; d<100000; d++){} } } + return (dhcp_state==2)?0:-1; +} diff --git a/src/kernel/network.h b/src/kernel/network.h new file mode 100644 index 0000000..95a2406 --- /dev/null +++ b/src/kernel/network.h @@ -0,0 +1,85 @@ +#ifndef NETWORK_H +#define NETWORK_H + +#include +#include +#include "e1000.h" + +#define ETH_FRAME_MAX_SIZE 1518 +#define ETH_HEADER_SIZE 14 +#define ETH_ETHERTYPE_ARP 0x0806 +#define ETH_ETHERTYPE_IPV4 0x0800 + +typedef struct { uint8_t bytes[6]; } mac_address_t; +typedef struct { uint8_t bytes[4]; } ipv4_address_t; + +typedef struct { + uint8_t dest_mac[6]; + uint8_t src_mac[6]; + uint16_t ethertype; +} __attribute__((packed)) eth_header_t; + +#define ARP_OP_REQUEST 1 +#define ARP_OP_REPLY 2 + +typedef struct { + uint16_t hw_type; + uint16_t proto_type; + uint8_t hw_len; + uint8_t proto_len; + uint16_t opcode; + uint8_t sender_mac[6]; + uint8_t sender_ip[4]; + uint8_t target_mac[6]; + uint8_t target_ip[4]; +} __attribute__((packed)) arp_header_t; + +#define IP_PROTO_UDP 17 + +typedef struct { + uint8_t version_ihl; + uint8_t tos; + uint16_t total_length; + uint16_t id; + uint16_t flags_frag; + uint8_t ttl; + uint8_t protocol; + uint16_t checksum; + uint8_t src_ip[4]; + uint8_t dest_ip[4]; +} __attribute__((packed)) ipv4_header_t; + +typedef struct { + uint16_t src_port; + uint16_t dest_port; + uint16_t length; + uint16_t checksum; +} __attribute__((packed)) udp_header_t; + +int network_init(void); +int network_get_mac_address(mac_address_t* mac); +int network_get_ipv4_address(ipv4_address_t* ip); +int network_set_ipv4_address(const ipv4_address_t* ip); +int network_send_frame(const void* data, size_t length); +int network_receive_frame(void* buffer, size_t buffer_size); +void network_process_frames(void); +int arp_send_request(const ipv4_address_t* target_ip); +int arp_lookup(const ipv4_address_t* ip, mac_address_t* mac); +void arp_process_packet(const arp_header_t* arp, size_t length); +int ipv4_send_packet(const ipv4_address_t* dest_ip, uint8_t protocol, const void* data, size_t data_length); +int ipv4_send_packet_to_mac(const ipv4_address_t* dest_ip, const mac_address_t* dest_mac, uint8_t protocol, const void* data, size_t data_length); +void ipv4_process_packet(const ipv4_header_t* ip, const mac_address_t* src_mac, size_t length); +int udp_send_packet(const ipv4_address_t* dest_ip, uint16_t dest_port, uint16_t src_port, const void* data, size_t data_length); +int udp_send_packet_to_mac(const ipv4_address_t* dest_ip, const mac_address_t* dest_mac, uint16_t dest_port, uint16_t src_port, const void* data, size_t data_length); +typedef void (*udp_callback_t)(const ipv4_address_t* src_ip, uint16_t src_port, const mac_address_t* src_mac, const void* data, size_t length); +int udp_register_callback(uint16_t port, udp_callback_t callback); +int network_is_initialized(void); +int network_get_frames_received(void); +int network_get_udp_packets_received(void); +int network_get_udp_callbacks_called(void); +int network_get_e1000_receive_calls(void); +int network_get_e1000_receive_empty(void); +int network_get_process_calls(void); +int network_dhcp_acquire(void); + +#endif diff --git a/src/kernel/pci.c b/src/kernel/pci.c new file mode 100644 index 0000000..f4dc71b --- /dev/null +++ b/src/kernel/pci.c @@ -0,0 +1,96 @@ +#include +#include "pci.h" +#include "io.h" + +uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) { + uint32_t address = (uint32_t)((1u << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC)); + outl(PCI_CONFIG_ADDRESS, address); + return inl(PCI_CONFIG_DATA); +} + +void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) { + uint32_t address = (uint32_t)((1u << 31) | (bus << 16) | (device << 11) | (function << 8) | (offset & 0xFC)); + outl(PCI_CONFIG_ADDRESS, address); + outl(PCI_CONFIG_DATA, value); +} + +int pci_device_exists(uint8_t bus, uint8_t device, uint8_t function) { + uint16_t vendor_id = pci_get_vendor_id(bus, device, function); + return vendor_id != 0xFFFF; +} + +uint16_t pci_get_vendor_id(uint8_t bus, uint8_t device, uint8_t function) { + uint32_t config = pci_read_config(bus, device, function, 0x00); + return (uint16_t)(config & 0xFFFF); +} + +uint16_t pci_get_device_id(uint8_t bus, uint8_t device, uint8_t function) { + uint32_t config = pci_read_config(bus, device, function, 0x00); + return (uint16_t)((config >> 16) & 0xFFFF); +} + +uint8_t pci_get_class_code(uint8_t bus, uint8_t device, uint8_t function) { + uint32_t config = pci_read_config(bus, device, function, 0x08); + return (uint8_t)((config >> 24) & 0xFF); +} + +uint8_t pci_get_subclass(uint8_t bus, uint8_t device, uint8_t function) { + uint32_t config = pci_read_config(bus, device, function, 0x08); + return (uint8_t)((config >> 16) & 0xFF); +} + +uint8_t pci_get_prog_if(uint8_t bus, uint8_t device, uint8_t function) { + uint32_t config = pci_read_config(bus, device, function, 0x08); + return (uint8_t)((config >> 8) & 0xFF); +} + +int pci_enumerate_devices(pci_device_t* devices, int max_devices) { + int count = 0; + for (uint8_t bus = 0; bus < 256 && count < max_devices; bus++) { + for (uint8_t dev = 0; dev < 32 && count < max_devices; dev++) { + if (pci_device_exists(bus, dev, 0)) { + uint32_t config_val = pci_read_config(bus, dev, 0, 0x0C); + uint8_t header_type = (uint8_t)((config_val >> 16) & 0xFF); + uint8_t num_functions = (header_type & 0x80) ? 8 : 1; + for (uint8_t fn = 0; fn < num_functions && count < max_devices; fn++) { + if (pci_device_exists(bus, dev, fn)) { + devices[count].bus = bus; + devices[count].device = dev; + devices[count].function = fn; + devices[count].vendor_id = pci_get_vendor_id(bus, dev, fn); + devices[count].device_id = pci_get_device_id(bus, dev, fn); + devices[count].class_code = pci_get_class_code(bus, dev, fn); + devices[count].subclass = pci_get_subclass(bus, dev, fn); + devices[count].prog_if = pci_get_prog_if(bus, dev, fn); + count++; + } + } + } + } + } + return count; +} + +int pci_find_device(uint16_t vendor_id, uint16_t device_id, pci_device_t* device) { + pci_device_t devices[32]; + int count = pci_enumerate_devices(devices, 32); + for (int i = 0; i < count; i++) { + if (devices[i].vendor_id == vendor_id && devices[i].device_id == device_id) { + *device = devices[i]; + return 1; + } + } + return 0; +} + +int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t* device) { + pci_device_t devices[32]; + int count = pci_enumerate_devices(devices, 32); + for (int i = 0; i < count; i++) { + if (devices[i].class_code == class_code && devices[i].subclass == subclass) { + *device = devices[i]; + return 1; + } + } + return 0; +} diff --git a/src/kernel/pci.h b/src/kernel/pci.h new file mode 100644 index 0000000..18ede63 --- /dev/null +++ b/src/kernel/pci.h @@ -0,0 +1,35 @@ +#ifndef PCI_H +#define PCI_H + +#include + +#define PCI_CONFIG_ADDRESS 0xCF8 +#define PCI_CONFIG_DATA 0xCFC + +typedef struct { + uint16_t vendor_id; + uint16_t device_id; + uint8_t bus; + uint8_t device; + uint8_t function; + uint8_t class_code; + uint8_t subclass; + uint8_t prog_if; +} pci_device_t; + +#define PCI_CLASS_NETWORK_CONTROLLER 0x02 +#define PCI_CLASS_ETHERNET_CONTROLLER 0x00 + +uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset); +void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value); +int pci_device_exists(uint8_t bus, uint8_t device, uint8_t function); +uint16_t pci_get_vendor_id(uint8_t bus, uint8_t device, uint8_t function); +uint16_t pci_get_device_id(uint8_t bus, uint8_t device, uint8_t function); +uint8_t pci_get_class_code(uint8_t bus, uint8_t device, uint8_t function); +uint8_t pci_get_subclass(uint8_t bus, uint8_t device, uint8_t function); +uint8_t pci_get_prog_if(uint8_t bus, uint8_t device, uint8_t function); +int pci_enumerate_devices(pci_device_t* devices, int max_devices); +int pci_find_device(uint16_t vendor_id, uint16_t device_id, pci_device_t* device); +int pci_find_device_by_class(uint8_t class_code, uint8_t subclass, pci_device_t* device); + +#endif diff --git a/src/kernel/platform.c b/src/kernel/platform.c new file mode 100644 index 0000000..a6caac0 --- /dev/null +++ b/src/kernel/platform.c @@ -0,0 +1,33 @@ +#include +#include "limine.h" +#include +static volatile struct limine_hhdm_request hhdm_request __attribute__((used, section(".requests"))) = { + .id = LIMINE_HHDM_REQUEST, + .revision = 0, + .response = NULL +}; +static volatile struct limine_kernel_address_request kernel_addr_request __attribute__((used, section(".requests"))) = { + .id = LIMINE_KERNEL_ADDRESS_REQUEST, + .revision = 0, + .response = NULL +}; +static uint64_t hhdm_offset = 0; +static uint64_t kernel_phys_base = 0; +static uint64_t kernel_virt_base = 0; +void platform_init(void) { + if (hhdm_request.response) { hhdm_offset = hhdm_request.response->offset; } + if (kernel_addr_request.response) { + kernel_phys_base = kernel_addr_request.response->physical_base; + kernel_virt_base = kernel_addr_request.response->virtual_base; + } +} +uint64_t p2v(uint64_t phys) { return phys + hhdm_offset; } +uint64_t v2p(uint64_t virt) { + if (kernel_virt_base && virt >= kernel_virt_base) { + return virt - kernel_virt_base + kernel_phys_base; + } + if (hhdm_offset && virt >= hhdm_offset) { + return virt - hhdm_offset; + } + return virt; +} diff --git a/src/kernel/platform.h b/src/kernel/platform.h new file mode 100644 index 0000000..092fb89 --- /dev/null +++ b/src/kernel/platform.h @@ -0,0 +1,10 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +#include + +void platform_init(void); +uint64_t p2v(uint64_t phys); +uint64_t v2p(uint64_t virt); + +#endif diff --git a/src/kernel/ps2.c b/src/kernel/ps2.c index cbf47cd..19a9806 100644 --- a/src/kernel/ps2.c +++ b/src/kernel/ps2.c @@ -1,6 +1,7 @@ #include "ps2.h" #include "io.h" #include "wm.h" +#include "network.h" #include extern void serial_print(const char *s); @@ -9,6 +10,7 @@ extern void serial_print_hex(uint64_t n); // --- Timer Handler --- void timer_handler(void) { wm_timer_tick(); + network_process_frames(); outb(0x20, 0x20); // EOI to Master PIC } @@ -164,4 +166,4 @@ void mouse_handler(void) { void ps2_init(void) { mouse_init(); -} \ No newline at end of file +}