New feature(s):
- Network stack
- Piping commands into a udpsend message
Bug fix(es):
-N/A
This commit is contained in:
Chris 2026-02-05 21:59:21 +01:00
parent d9fc8fbeda
commit 89bdb860dd
34 changed files with 1322 additions and 16 deletions

View file

@ -119,4 +119,5 @@ clean:
run: $(ISO_IMAGE) run: $(ISO_IMAGE)
qemu-system-x86_64 -m 2G -serial stdio -cdrom $(ISO_IMAGE) -boot d \ 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

View file

@ -1,4 +1,4 @@
# Brew OS 1.03 Pre-Alpha # Brew OS 1.10 Alpha
## Brewkernel is now BrewOS! ## 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). 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! It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more!
## Features ## Features
- Basic Networking Stack
- Brew WM - Brew WM
- Fat 32 FS - Fat 32 FS
- 64-bit long mode support - 64-bit long mode support

Binary file not shown.

Binary file not shown.

BIN
build/cli_apps/net.o Normal file

Binary file not shown.

BIN
build/cli_apps/pci_list.o Normal file

Binary file not shown.

Binary file not shown.

BIN
build/e1000.o Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build/network.o Normal file

Binary file not shown.

BIN
build/pci.o Normal file

Binary file not shown.

BIN
build/platform.o Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,4 @@
# Brew OS 1.01 Alpha # Brew OS 1.03 Pre-Alpha
## Brewkernel is now BrewOS! ## 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). 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).

Binary file not shown.

View file

@ -35,8 +35,8 @@ static void about_paint(Window *win) {
// Version info // Version info
draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK); 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 + 120, "BrewOS Version 1.10", COLOR_BLACK);
draw_string(offset_x, offset_y + 135, "Kernel Version 2.0.3", COLOR_BLACK); draw_string(offset_x, offset_y + 135, "Kernel Version 2.1.0", COLOR_BLACK);
// Copyright // Copyright
draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK); draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK);

View file

@ -2,6 +2,6 @@
void cli_cmd_brewver(char *args) { void cli_cmd_brewver(char *args) {
(void)args; (void)args;
cli_write("BrewOS v1.03 Alpha\n"); cli_write("BrewOS v1.10 Alpha\n");
cli_write("BrewOS Kernel V2.0.3 Pre-Alpha\n"); cli_write("BrewOS Kernel V2.1.0 Pre-Alpha\n");
} }

View file

@ -37,4 +37,14 @@ void cli_cmd_memblock(char *args);
void cli_cmd_memvalid(char *args); void cli_cmd_memvalid(char *args);
void cli_cmd_memtest(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 #endif

112
src/kernel/cli_apps/net.c Normal file
View file

@ -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;i<length;i++){ cli_putchar(((const char*)data)[i]); }
cli_write("\n");
}
void cli_cmd_udptest(char *args){
if(!args||!*args){ cli_write("Usage: UDPTEST port\n"); return; }
int port=cli_atoi(args);
if(port<=0||port>65535){ 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");
}

View file

@ -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<n;i++){
cli_write(" ");
cli_write_int(devs[i].bus); cli_write(":");
cli_write_int(devs[i].device); cli_write(".");
cli_write_int(devs[i].function); cli_write(" ");
cli_write("vendor="); print_hex16(devs[i].vendor_id); cli_write(" ");
cli_write("device="); print_hex16(devs[i].device_id); cli_write(" ");
cli_write("class="); print_hex8(devs[i].class_code); cli_write(" ");
cli_write("subclass="); print_hex8(devs[i].subclass); cli_write(" ");
cli_write("prog_if="); print_hex8(devs[i].prog_if);
if(devs[i].vendor_id==0x8086 && devs[i].device_id==0x100E){
cli_write(" [e1000]");
}
cli_write("\n");
}
cli_write_int(n); cli_write(" device(s)\n");
}

View file

@ -13,6 +13,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include "network.h"
#define CMD_COLS 116 #define CMD_COLS 116
#define CMD_ROWS 41 #define CMD_ROWS 41
@ -112,6 +113,9 @@ int boot_time_init = 0;
// Output redirection state // Output redirection state
static FAT32_FileHandle *redirect_file = NULL; static FAT32_FileHandle *redirect_file = NULL;
static char redirect_mode = 0; // '>' for write, 'a' for append, 0 for normal output 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; int boot_year, boot_month, boot_day, boot_hour, boot_min, boot_sec;
// --- Helpers --- // --- Helpers ---
@ -197,6 +201,14 @@ static void cmd_scroll_up() {
// Public for CLI apps to use // Public for CLI apps to use
void cmd_putchar(char c) { 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 output is being redirected to a file, write there instead
if (redirect_file && redirect_mode) { if (redirect_file && redirect_mode) {
fat32_write(redirect_file, &c, 1); fat32_write(redirect_file, &c, 1);
@ -235,6 +247,14 @@ void cmd_putchar(char c) {
// Public for CLI apps to use // Public for CLI apps to use
void cmd_write(const char *str) { 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 output is being redirected to a file, write there instead
if (redirect_file && redirect_mode) { if (redirect_file && redirect_mode) {
fat32_write(redirect_file, (void *)str, cmd_strlen(str)); fat32_write(redirect_file, (void *)str, cmd_strlen(str));
@ -402,19 +422,33 @@ static const CommandEntry commands[] = {
{"memvalid", cli_cmd_memvalid}, {"memvalid", cli_cmd_memvalid},
{"MEMTEST", cli_cmd_memtest}, {"MEMTEST", cli_cmd_memtest},
{"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} {NULL, NULL}
}; };
// --- Dispatcher --- // --- Dispatcher ---
// Buffer for capturing command output // Find pipe operator in command string (||)
static char pipe_buffer[8192]; static const char* find_pipe(const char* cmd) {
static int pipe_buffer_pos = 0; while (*cmd) {
if (*cmd == '|' && *(cmd + 1) == '|') {
static void pipe_capture_write(const char *str) { return cmd;
while (*str && pipe_buffer_pos < (int)sizeof(pipe_buffer) - 1) { }
pipe_buffer[pipe_buffer_pos++] = *str++; cmd++;
} }
return NULL;
} }
// Execute a single command // Execute a single command
@ -445,6 +479,160 @@ static void cmd_exec_single(char *cmd) {
// Execute command with redirection and pipe support // Execute command with redirection and pipe support
static void cmd_exec(char *cmd) { 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 >>) // Check for redirection operators (> or >>)
char *redirect_ptr = NULL; char *redirect_ptr = NULL;
char redirect_op = 0; // '>' or 'a' for append char redirect_op = 0; // '>' or 'a' for append

145
src/kernel/e1000.c Normal file
View file

@ -0,0 +1,145 @@
#include <stdint.h>
#include <stddef.h>
#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;
}

99
src/kernel/e1000.h Normal file
View file

@ -0,0 +1,99 @@
#ifndef E1000_H
#define E1000_H
#include <stdint.h>
#include <stddef.h>
#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

View file

@ -17,6 +17,16 @@ static inline uint8_t inb(uint16_t port) {
return ret; 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) { static inline void io_wait(void) {
outb(0x80, 0); outb(0x80, 0);
} }

View file

@ -8,6 +8,7 @@
#include "wm.h" #include "wm.h"
#include "io.h" #include "io.h"
#include "memory_manager.h" #include "memory_manager.h"
#include "platform.h"
// --- Limine Requests --- // --- Limine Requests ---
__attribute__((used, section(".requests"))) __attribute__((used, section(".requests")))
@ -46,6 +47,7 @@ static void hcf(void) {
// Kernel Entry Point // Kernel Entry Point
void kmain(void) { void kmain(void) {
platform_init();
// 1. Graphics Init // 1. Graphics Init
if (LIMINE_BASE_REVISION_SUPPORTED == false) { if (LIMINE_BASE_REVISION_SUPPORTED == false) {
// Warning // Warning

433
src/kernel/network.c Normal file
View file

@ -0,0 +1,433 @@
#include <stdint.h>
#include <stddef.h>
#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<n;i++)D[i]=S[i];return d;}
static void* kmemset(void* d,int v,size_t n){uint8_t*D=d;for(size_t i=0;i<n;i++)D[i]=(uint8_t)v;return d;}
static int kmemcmp(const void* a,const void* b,size_t n){const uint8_t*A=a;const uint8_t*B=b;for(size_t i=0;i<n;i++){if(A[i]!=B[i])return (int)A[i]-(int)B[i];}return 0;}
static uint16_t htons(uint16_t x){return (uint16_t)(((x&0xFF)<<8)|((x>>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;i<ARP_CACHE_SIZE;i++){ if(arp_cache[i].valid && kmemcmp(&arp_cache[i].ip, ip, sizeof(ipv4_address_t))==0) return &arp_cache[i]; } return NULL; }
static void arp_cache_add(const ipv4_address_t* ip,const mac_address_t* mac){ arp_cache_entry_t* e=arp_cache_find(ip); if(e){ kmemcpy(&e->mac,mac,sizeof(mac_address_t)); e->timestamp=0; return;} for(int i=0;i<ARP_CACHE_SIZE;i++){ if(!arp_cache[i].valid){ kmemcpy(&arp_cache[i].ip,ip,sizeof(ipv4_address_t)); kmemcpy(&arp_cache[i].mac,mac,sizeof(mac_address_t)); arp_cache[i].timestamp=0; arp_cache[i].valid=1; return; } } kmemcpy(&arp_cache[0].ip,ip,sizeof(ipv4_address_t)); kmemcpy(&arp_cache[0].mac,mac,sizeof(mac_address_t)); arp_cache[0].timestamp=0; arp_cache[0].valid=1; }
int network_init(void){
if(network_initialized) return 0;
pci_device_t device;
if(!pci_find_device(E1000_VENDOR_ID,E1000_DEVICE_ID_82540EM,&device)) return -1;
if(e1000_init(&device)!=0) return -1;
if(network_get_mac_address(&our_mac)!=0) return -1;
arp_cache_init();
kmemset(udp_callbacks,0,sizeof(udp_callbacks));
network_initialized=1;
return 0;
}
int network_get_mac_address(mac_address_t* mac){
e1000_device_t* dev=e1000_get_device();
if(!dev) return -1;
*mac=*(mac_address_t*)&dev->mac_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(length<sizeof(arp_header_t)) return;
if(ntohs(arp->hw_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(length<sizeof(ipv4_header_t)) return;
uint8_t ihl=(ip->version_ihl & 0x0F)*4;
if(ihl<20 || length<ihl) return;
uint16_t total_length=ntohs(ip->total_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;i<UDP_MAX_CALLBACKS;i++){
if(udp_callbacks[i].valid && udp_callbacks[i].port==dest_port){
udp_callbacks_called_count++;
udp_callbacks[i].callback(&src_ip,src_port,src_mac,udp_payload,udp_payload_length);
return;
}
}
}
}
}
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){
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(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<UDP_MAX_CALLBACKS;i++){
if(!udp_callbacks[i].valid || udp_callbacks[i].port==port){
udp_callbacks[i].port=port;
udp_callbacks[i].callback=callback;
udp_callbacks[i].valid=1;
return 0;
}
}
return -1;
}
int network_is_initialized(void){ return network_initialized; }
int network_get_frames_received(void){ return frames_received_count; }
int network_get_udp_packets_received(void){ return udp_packets_received_count; }
int network_get_udp_callbacks_called(void){ return udp_callbacks_called_count; }
int network_get_e1000_receive_calls(void){ return e1000_receive_calls; }
int network_get_e1000_receive_empty(void){ return e1000_receive_empty; }
int network_get_process_calls(void){ return network_process_calls; }
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
#define DHCP_MAGIC_COOKIE 0x63825363U
#define DHCP_OP_BOOTREQUEST 1
#define DHCP_OP_BOOTREPLY 2
#define DHCP_HTYPE_ETHERNET 1
#define DHCP_HLEN_ETHERNET 6
#define DHCP_MSG_DISCOVER 1
#define DHCP_MSG_OFFER 2
#define DHCP_MSG_REQUEST 3
#define DHCP_MSG_ACK 5
#define DHCP_MSG_NAK 6
#define DHCP_OPT_MSG_TYPE 53
#define DHCP_OPT_SERVER_ID 54
#define DHCP_OPT_REQ_IP 50
#define DHCP_OPT_PARAM_REQ_LIST 55
#define DHCP_OPT_END 255
typedef struct {
uint8_t op;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t flags;
uint32_t ciaddr;
uint32_t yiaddr;
uint32_t siaddr;
uint32_t giaddr;
uint8_t chaddr[16];
uint8_t sname[64];
uint8_t file[128];
uint32_t magic_cookie;
uint8_t options[312];
} __attribute__((packed)) dhcp_packet_t;
static volatile int dhcp_state = 0;
static uint32_t dhcp_xid = 0;
static ipv4_address_t dhcp_offered_ip;
static uint32_t dhcp_server_id = 0;
static uint32_t htonl32(uint32_t v){return ((v&0xFF)<<24)|((v&0xFF00)<<8)|((v>>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_length<sizeof(dhcp_packet_t)-312) return;
dhcp_packet_t* pkt=(dhcp_packet_t*)payload;
if(pkt->op!=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;
}

85
src/kernel/network.h Normal file
View file

@ -0,0 +1,85 @@
#ifndef NETWORK_H
#define NETWORK_H
#include <stdint.h>
#include <stddef.h>
#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

96
src/kernel/pci.c Normal file
View file

@ -0,0 +1,96 @@
#include <stdint.h>
#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;
}

35
src/kernel/pci.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef PCI_H
#define PCI_H
#include <stdint.h>
#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

33
src/kernel/platform.c Normal file
View file

@ -0,0 +1,33 @@
#include <stdint.h>
#include "limine.h"
#include <stddef.h>
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;
}

10
src/kernel/platform.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef PLATFORM_H
#define PLATFORM_H
#include <stdint.h>
void platform_init(void);
uint64_t p2v(uint64_t phys);
uint64_t v2p(uint64_t virt);
#endif

View file

@ -1,6 +1,7 @@
#include "ps2.h" #include "ps2.h"
#include "io.h" #include "io.h"
#include "wm.h" #include "wm.h"
#include "network.h"
#include <stdbool.h> #include <stdbool.h>
extern void serial_print(const char *s); extern void serial_print(const char *s);
@ -9,6 +10,7 @@ extern void serial_print_hex(uint64_t n);
// --- Timer Handler --- // --- Timer Handler ---
void timer_handler(void) { void timer_handler(void) {
wm_timer_tick(); wm_timer_tick();
network_process_frames();
outb(0x20, 0x20); // EOI to Master PIC outb(0x20, 0x20); // EOI to Master PIC
} }