From dcdb67306f1e76170c25dcfdd5807c1c2917e024 Mon Sep 17 00:00:00 2001 From: Atheria Date: Mon, 11 Aug 2025 13:32:02 +0700 Subject: [PATCH 1/2] RTL8139 --- drivers/PCI/PCI.c | 97 ++++++++++++++++++++++++++++++++------ drivers/PCI/PCI.h | 24 ++++++++-- drivers/ethernet/Packet.h | 37 +++++++++++++++ drivers/ethernet/RTL8139.c | 97 ++++++++++++++++++++++++++++++++++++++ drivers/ethernet/RTL8139.h | 67 ++++++++++++++++++++++---- kernel/core/Kernel.c | 7 ++- kernel/etc/Shell.c | 61 +++++++++++++++++++++++- meson.build | 3 ++ 8 files changed, 362 insertions(+), 31 deletions(-) create mode 100644 drivers/ethernet/Packet.h diff --git a/drivers/PCI/PCI.c b/drivers/PCI/PCI.c index 581f5c8..07e0987 100644 --- a/drivers/PCI/PCI.c +++ b/drivers/PCI/PCI.c @@ -1,9 +1,16 @@ -#include "PCI.h" +#include "PCI/PCI.h" #include "Console.h" #include "Io.h" #include "stdint.h" +static PciDevice found_device; +static int device_found_flag; +static uint16_t target_vendor_id; +static uint16_t target_device_id; +// Callback function pointer type +typedef void (*PciDeviceCallback)(PciDevice device); + uint32_t PciConfigReadDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { uint32_t address; uint32_t lbus = (uint32_t)bus; @@ -21,21 +28,81 @@ uint8_t PciConfigReadByte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offse return PciConfigReadDWord(bus, slot, func, offset) & 0xFF; } -void PciEnumerate() { - for (uint8_t bus = 0; bus < 255; bus++) { - for (uint8_t device = 0; device < 32; device++) { - for (uint8_t func = 0; func < 8; func++) { - const uint32_t data = PciConfigReadDWord(bus, device, func, 0x00); - const uint16_t vendor_id = data & 0xFFFF; - if (vendor_id == 0xFFFF) continue; // No device here - const uint16_t device_id = (data >> 16) & 0xFFFF; - PrintKernel("PCI Device: Bus "); PrintKernelHex(bus); - PrintKernel(", Device "); PrintKernelHex(device); - PrintKernel(", Func "); PrintKernelHex(func); - PrintKernel(", Vendor 0x"); PrintKernelHex(vendor_id); - PrintKernel(", Device 0x"); PrintKernelHex(device_id); - PrintKernel("\n"); +// The core scanning logic, now separated and reusable +static void PciScanBus(PciDeviceCallback callback) { + for (int bus = 0; bus < 256; bus++) { + for (int device = 0; device < 32; device++) { + // Read header type to check for multi-function devices + uint32_t header_type_reg = PciConfigReadDWord(bus, device, 0, 0x0C); + uint8_t header_type = (header_type_reg >> 16) & 0xFF; + int max_funcs = (header_type & 0x80) ? 8 : 1; // Is multi-function bit set? + + for (int func = 0; func < max_funcs; func++) { + uint32_t id_reg = PciConfigReadDWord(bus, device, func, 0x00); + uint16_t vendor_id = id_reg & 0xFFFF; + + if (vendor_id == 0xFFFF) continue; // Device doesn't exist + + PciDevice pci_dev; + pci_dev.bus = bus; + pci_dev.device = device; + pci_dev.function = func; + pci_dev.vendor_id = vendor_id; + pci_dev.device_id = id_reg >> 16; + + uint32_t class_reg = PciConfigReadDWord(bus, device, func, 0x08); + pci_dev.class_code = (class_reg >> 24) & 0xFF; + pci_dev.subclass = (class_reg >> 16) & 0xFF; + pci_dev.prog_if = (class_reg >> 8) & 0xFF; + + // Call the provided callback with the device info + callback(pci_dev); } } } } + +// Your old PciEnumerate function, now a simple wrapper around the scanner +static void PrintPciDeviceInfo(PciDevice device) { + PrintKernel("PCI: B:0x"); PrintKernelHex(device.bus); + PrintKernel(" D:0x"); PrintKernelHex(device.device); + PrintKernel(" F:0x"); PrintKernelHex(device.function); + PrintKernel(" -> VID:0x"); PrintKernelHex(device.vendor_id); + PrintKernel(" DID:0x"); PrintKernelHex(device.device_id); + PrintKernel(" (C:0x"); PrintKernelHex(device.class_code); + PrintKernel(" S:0x"); PrintKernelHex(device.subclass); + PrintKernel(")\n"); +} + +void PciEnumerate() { + PrintKernel("--- PCI Bus Enumeration ---\n"); + PciScanBus(PrintPciDeviceInfo); + PrintKernel("---------------------------\n"); +} + +static void FindDeviceCallback(PciDevice device) { + if (device_found_flag) return; // We already found it, stop searching + + if (device.vendor_id == target_vendor_id && device.device_id == target_device_id) { + found_device = device; + device_found_flag = 1; + } +} + +// The public helper function to find a device +int PciFindDevice(uint16_t vendor_id, uint16_t device_id, PciDevice* out_device) { + // Set up the search criteria + target_vendor_id = vendor_id; + target_device_id = device_id; + device_found_flag = 0; + + // Scan the bus using our specific search callback + PciScanBus(FindDeviceCallback); + + if (device_found_flag) { + *out_device = found_device; + return 0; // Success + } + + return -1; // Failure +} \ No newline at end of file diff --git a/drivers/PCI/PCI.h b/drivers/PCI/PCI.h index 489f815..a1aed2b 100644 --- a/drivers/PCI/PCI.h +++ b/drivers/PCI/PCI.h @@ -1,9 +1,23 @@ -#ifndef VOIDFRAME_PCI_H -#define VOIDFRAME_PCI_H +#ifndef PCI_H +#define PCI_H -#define PCI_CONFIG_ADDRESS 0xCF8 -#define PCI_CONFIG_DATA 0xCFC +#include "stdint.h" // Or your equivalent for standard types +// A structure to hold information about a discovered PCI device +typedef struct { + uint8_t bus; + uint8_t device; + uint8_t function; + uint16_t vendor_id; + uint16_t device_id; + uint8_t class_code; + uint8_t subclass; + uint8_t prog_if; // Programming Interface +} PciDevice; + +// Function prototypes void PciEnumerate(); +int PciFindDevice(uint16_t vendor_id, uint16_t device_id, PciDevice* out_device); +uint32_t PciConfigReadDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset); -#endif // VOIDFRAME_PCI_H +#endif // PCI_H \ No newline at end of file diff --git a/drivers/ethernet/Packet.h b/drivers/ethernet/Packet.h new file mode 100644 index 0000000..04c5e91 --- /dev/null +++ b/drivers/ethernet/Packet.h @@ -0,0 +1,37 @@ +#ifndef PACKET_H +#define PACKET_H + +#include + +// Endianness conversion - crucial for network packets +// Network byte order is Big Endian, x86 is Little Endian. +#define HTONS(n) ((((n) & 0xFF) << 8) | (((n) & 0xFF00) >> 8)) + +// Ethernet Header (14 bytes) +typedef struct { + uint8_t dest_mac[6]; + uint8_t src_mac[6]; + uint16_t ethertype; +} __attribute__((packed)) EthernetHeader; + +// ARP Packet (28 bytes) +typedef struct { + uint16_t hardware_type; // 1 for Ethernet + uint16_t protocol_type; // 0x0800 for IPv4 + uint8_t hardware_addr_len; // 6 for MAC + uint8_t protocol_addr_len; // 4 for IP + uint16_t opcode; // 1 for request, 2 for reply + uint8_t sender_mac[6]; + uint8_t sender_ip[4]; + uint8_t target_mac[6]; + uint8_t target_ip[4]; +} __attribute__((packed)) ArpPacket; + +// Full ARP-over-Ethernet Packet (42 bytes) +typedef struct { + EthernetHeader eth; + ArpPacket arp; +} __attribute__((packed)) FullArpPacket; + + +#endif // PACKET_H \ No newline at end of file diff --git a/drivers/ethernet/RTL8139.c b/drivers/ethernet/RTL8139.c index 7ea80fc..bac5f5f 100644 --- a/drivers/ethernet/RTL8139.c +++ b/drivers/ethernet/RTL8139.c @@ -1,2 +1,99 @@ #include "RTL8139.h" + +#include "Console.h" +#include "Io.h" +#include "KernelHeap.h" // For allocating memory +#include "MemOps.h" + +// Global device object +static Rtl8139Device rtl_device; + +void Rtl8139_Init() { + PrintKernel("Searching for RTL8139 (10EC:8139)...\n"); + + if (PciFindDevice(0x10EC, 0x8139, &rtl_device.pci_info) != 0) { + PrintKernel("RTL8139 Network Card not found.\n"); + return; + } + PrintKernel("Found RTL8139!\n"); + + // --- Part 1: Read BAR0 and get the I/O base address --- + uint32_t bar0 = PciConfigReadDWord(rtl_device.pci_info.bus, rtl_device.pci_info.device, rtl_device.pci_info.function, 0x10); + rtl_device.io_base = bar0 & 0xFFFC; + PrintKernel("I/O Base: 0x"); PrintKernelHex(rtl_device.io_base); PrintKernel("\n"); + + // --- Part 2: Power on and Reset --- + outb(rtl_device.io_base + REG_CONFIG_1, 0x00); + outb(rtl_device.io_base + REG_COMMAND, CMD_RESET); + while ((inb(rtl_device.io_base + REG_COMMAND) & CMD_RESET) != 0) { /* wait */ } + PrintKernel("RTL8139 reset complete.\n"); + + // --- Part 2.1: Reading MAC address --- + PrintKernel("Reading MAC Address: "); + for (int i = 0; i < 6; i++) { + rtl_device.mac_address[i] = inb(rtl_device.io_base + REG_MAC0 + i); + PrintKernelHex(rtl_device.mac_address[i]); + if (i < 5) PrintKernel(":"); + } + PrintKernel("\n"); + + // --- Part 3: Allocate Buffers for DMA --- + // NOTE: This MUST be physically contiguous memory! For now, we assume KernelMemoryAlloc does this. + // In a real OS, you'd need a proper physical memory manager. + rtl_device.rx_buffer = KernelMemoryAlloc(RX_BUFFER_SIZE); + for (int i = 0; i < TX_BUFFER_COUNT; i++) { + rtl_device.tx_buffers[i] = KernelMemoryAlloc(2048); // 2K per TX buffer + } + rtl_device.current_tx_buffer = 0; + PrintKernel("DMA buffers allocated.\n"); + + // --- Part 4: Tell the card where the receive buffer is --- + // The hardware needs the PHYSICAL address of the buffer. + uint32_t rx_phys_addr = (uint32_t)rtl_device.rx_buffer; // Assuming identity mapping for now + outl(rtl_device.io_base + REG_RX_BUFFER_START, rx_phys_addr); + PrintKernel("Receive buffer configured.\n"); + + // --- Part 5: Enable the Receiver and Transmitter --- + // This is the final step to "turn on" the card. + outb(rtl_device.io_base + REG_COMMAND, CMD_TX_ENABLE | CMD_RX_ENABLE); + PrintKernel("Transmitter and Receiver enabled.\n"); + + // Configure Rx register: accept broadcast, multicast, and packets for our MAC (AB+AM+APM) + // and wrap packets that are too long. + outl(rtl_device.io_base + REG_RX_CONFIG, 0x0F); + + PrintKernel("RTL8139 initialization finished!\n"); +} + +void Rtl8139_SendPacket(void* data, uint32_t len) { + if (len > 2048) { + PrintKernel("Packet too large to send.\n"); + return; + } + + // Get the I/O and memory addresses for the current transmit descriptor + int tx_index = rtl_device.current_tx_buffer; + uint32_t tx_addr_reg = REG_TX_ADDR_0 + (tx_index * 4); + uint32_t tx_stat_reg = REG_TX_STATUS_0 + (tx_index * 4); + uint8_t* tx_buffer = rtl_device.tx_buffers[tx_index]; + + // Copy the packet data to our DMA-safe buffer + FastMemcpy(tx_buffer, data, len); + + // Tell the card where the data is (physical address) + uint32_t tx_phys_addr = (uint32_t)tx_buffer; + outl(rtl_device.io_base + tx_addr_reg, tx_phys_addr); + + // Tell the card the length of the data and start sending! + outl(rtl_device.io_base + tx_stat_reg, len); + + PrintKernel("Sent packet of "); PrintKernelInt(len); PrintKernel(" bytes.\n"); + + // Move to the next transmit buffer for the next send operation + rtl_device.current_tx_buffer = (tx_index + 1) % TX_BUFFER_COUNT; +} + +const Rtl8139Device* GetRtl8139Device() { + return &rtl_device; +} \ No newline at end of file diff --git a/drivers/ethernet/RTL8139.h b/drivers/ethernet/RTL8139.h index a1ceadf..8265caa 100644 --- a/drivers/ethernet/RTL8139.h +++ b/drivers/ethernet/RTL8139.h @@ -1,11 +1,60 @@ -#ifndef VOIDFRAME_RTL8139_H -#define VOIDFRAME_RTL8139_H +#ifndef RTL8139_H +#define RTL8139_H -#define MAC0 0x00 -#define MAR0 0x08 -#define RBSTART 0x30 -#define CMD 0x37 -#define IMR 0x3C -#define ISR 0x3E +#include +#include "PCI/PCI.h" -#endif // VOIDFRAME_RTL8139_H +// ============================================================================= +// RTL8139 Register Offsets (from the I/O base address) +// ============================================================================= +#define REG_MAC0 0x00 // MAC Address (6 bytes) +#define REG_MAR0 0x08 // Multicast Address Register (8 bytes) +#define REG_TX_STATUS_0 0x10 // Transmit Status of Descriptor 0 (4 bytes) +#define REG_TX_ADDR_0 0x20 // Transmit Address of Descriptor 0 (4 bytes) +#define REG_RX_BUFFER_START 0x30 // Receive Buffer Start Address (RBSTART) +#define REG_COMMAND 0x37 // Command Register (1 byte) +#define REG_CAPR 0x38 // Current Address of Packet Read (2 bytes) +#define REG_IMR 0x3C // Interrupt Mask Register (2 bytes) +#define REG_ISR 0x3E // Interrupt Service Register (2 bytes) +#define REG_TX_CONFIG 0x40 // Tx Config Register (4 bytes) +#define REG_RX_CONFIG 0x44 // Rx Config Register (4 bytes) +#define REG_CONFIG_1 0x52 // Config Register 1 (1 byte) + +// ============================================================================= +// Command Register (REG_COMMAND) Bits +// ============================================================================= +#define CMD_BUFFER_EMPTY (1 << 0) // Is receive buffer empty? +#define CMD_TX_ENABLE (1 << 2) // Enable Transmitter +#define CMD_RX_ENABLE (1 << 3) // Enable Receiver +#define CMD_RESET (1 << 4) // Software Reset + +// ============================================================================= +// Interrupt Service/Mask Register (ISR/IMR) Bits +// ============================================================================= +#define ISR_RX_OK (1 << 0) // Receive OK +#define ISR_TX_OK (1 << 2) // Transmit OK +#define ISR_RX_ERR (1 << 1) // Receive Error +#define ISR_TX_ERR (1 << 3) // Transmit Error + +// ============================================================================= +// Driver Configuration Constants +// ============================================================================= +#define RX_BUFFER_SIZE (8192 + 16) // 8K + 16-byte header +#define TX_BUFFER_COUNT 4 // Use all 4 hardware transmit buffers + +// Device state structure +typedef struct { + PciDevice pci_info; + uint32_t io_base; + uint8_t mac_address[6]; + uint8_t* rx_buffer; + uint8_t* tx_buffers[TX_BUFFER_COUNT]; + int current_tx_buffer; +} Rtl8139Device; + +// Function Prototypes +void Rtl8139_Init(); +void Rtl8139_SendPacket(void* data, uint32_t len); +const Rtl8139Device* GetRtl8139Device(); + +#endif // RTL8139_H \ No newline at end of file diff --git a/kernel/core/Kernel.c b/kernel/core/Kernel.c index 71d0dc8..7fc8750 100644 --- a/kernel/core/Kernel.c +++ b/kernel/core/Kernel.c @@ -10,11 +10,13 @@ #include "MemPool.h" #include "Memory.h" #include "Multiboot2.h" +#include "PCI/PCI.h" #include "PS2.h" #include "Paging.h" #include "Panic.h" #include "Pic.h" #include "Process.h" +#include "ethernet/RTL8139.h" #include "Serial.h" #include "Shell.h" #include "StackGuard.h" @@ -24,7 +26,6 @@ #include "VesaBIOSExtension.h" #include "stdbool.h" #include "stdint.h" -#include "PCI/PCI.h" void KernelMainHigherHalf(void); #define KERNEL_STACK_SIZE (16 * 1024) // 16KB stack @@ -381,6 +382,10 @@ static InitResultT SystemInitS2(void) { PciEnumerate(); PrintKernelSuccess("[SYSTEM] PCI devices scanned\n"); + PrintKernel("[INFO] Initializing RTL8139 Driver...\n"); + Rtl8139_Init(); + PrintKernelSuccess("[SYSTEM] RTL8139 Driver initialized\n"); + // NEW: Final memory health check PrintKernel("[INFO] Final memory health check...\n"); GetDetailedMemoryStats(&stats); diff --git a/kernel/etc/Shell.c b/kernel/etc/Shell.c index ffb7e5c..b42b2b8 100644 --- a/kernel/etc/Shell.c +++ b/kernel/etc/Shell.c @@ -14,6 +14,8 @@ #include "VMem.h" #include "VesaBIOSExtension.h" #include "stdlib.h" +#include "Packet.h" +#include "RTL8139.h" static char command_buffer[256]; static int cmd_pos = 0; @@ -73,6 +75,60 @@ static char* GetArg(const char* cmd, int arg_num) { return NULL; } +void ArpRequestTestProcess() { + FullArpPacket packet; + + // Get the network card's info, especially our MAC address + const Rtl8139Device* nic = GetRtl8139Device(); + if (!nic) { + // Handle error: NIC not initialized + return; + } + + // --- Part 1: Build the Ethernet Header --- + + // Destination MAC: FF:FF:FF:FF:FF:FF (Broadcast) + FastMemset(packet.eth.dest_mac, 0xFF, 6); + + // Source MAC: Our card's MAC address + FastMemcpy(packet.eth.src_mac, nic->mac_address, 6); + + // EtherType: 0x0806 for ARP + packet.eth.ethertype = HTONS(0x0806); + + // --- Part 2: Build the ARP Packet --- + + packet.arp.hardware_type = HTONS(1); // 1 = Ethernet + packet.arp.protocol_type = HTONS(0x0800); // 0x0800 = IPv4 + packet.arp.hardware_addr_len = 6; + packet.arp.protocol_addr_len = 4; + packet.arp.opcode = HTONS(1); // 1 = ARP Request + + // Sender MAC: Our MAC address + FastMemcpy(packet.arp.sender_mac, nic->mac_address, 6); + + // Sender IP: We don't have an IP stack, so let's pretend we're 192.168.1.100 + packet.arp.sender_ip[0] = 192; + packet.arp.sender_ip[1] = 168; + packet.arp.sender_ip[2] = 1; + packet.arp.sender_ip[3] = 100; + + // Target MAC: 00:00:00:00:00:00 (this is what we're asking for) + FastMemset(packet.arp.target_mac, 0x00, 6); + + // Target IP: The IP of the computer we want to find (e.g., your router) + packet.arp.target_ip[0] = 192; + packet.arp.target_ip[1] = 168; + packet.arp.target_ip[2] = 1; + packet.arp.target_ip[3] = 1; + + // --- Part 3: Send the packet! --- + + // The total packet size is the size of the two headers + uint32_t packet_size = sizeof(EthernetHeader) + sizeof(ArpPacket); + Rtl8139_SendPacket(&packet, packet_size); +} + static void ResolvePath(const char* input, char* output, int max_len) { if (!input || !output) return; @@ -113,6 +169,7 @@ static void show_help() { PrintKernel(" perf - Show performance stats\n"); PrintKernel(" memstat - Show memory statistics\n"); PrintKernel(" pciscan - Perform a PCI scan\n"); + PrintKernel(" arptest - Perform an ARP test and send packets\n"); PrintKernel(" clear - Clear screen\n"); PrintKernel(" info - A piece information about the kernel\n"); PrintKernel(" cd - Change directory\n"); @@ -123,7 +180,7 @@ static void show_help() { PrintKernel(" touch - Create empty file\n"); PrintKernel(" alloc - Allocate bytes\n"); PrintKernel(" panic - Panic with \n"); - PrintKernel(" kill - Terminate process with pid \n"); + PrintKernel(" kill - Terminate process with pid \n"); PrintKernel(" rm - Remove file or empty directory\n"); PrintKernel(" echo - Write text to file\n"); PrintKernel(" fstest - Run filesystem tests\n"); @@ -217,6 +274,8 @@ static void ExecuteCommand(const char* cmd) { } else if (FastStrCmp(cmd_name, "pwd") == 0) { PrintKernel(current_dir); PrintKernel("\n"); + } else if (FastStrCmp(cmd_name, "arptest") == 0) { + CreateProcess(ArpRequestTestProcess); } else if (FastStrCmp(cmd_name, "ls") == 0) { char* path = GetArg(cmd, 1); if (!path) { diff --git a/meson.build b/meson.build index 02caa2c..97ab237 100644 --- a/meson.build +++ b/meson.build @@ -45,6 +45,8 @@ inc_dirs = [ src_root + '/kernel/etc', src_root + '/kernel/graphics', src_root + '/drivers', + src_root + '/drivers/PCI', + src_root + '/drivers/ethernet', src_root + '/fs', arch_root + '/cpu', arch_root + '/gdt', @@ -92,6 +94,7 @@ c_sources = [ src_root + '/drivers/Ide.c', src_root + '/drivers/VesaBIOSExtension.c', src_root + '/drivers/PCI/PCI.c', + src_root + '/drivers/ethernet/RTL8139.c', arch_root + '/idt/Idt.c', arch_root + '/gdt/Gdt.c', arch_root + '/syscall/Syscall.c', From 699b1f1147b5d30837420b982935298830515eaa Mon Sep 17 00:00:00 2001 From: Atheria Date: Mon, 11 Aug 2025 14:19:17 +0700 Subject: [PATCH 2/2] RTL8139 --- drivers/PCI/PCI.c | 7 ------- drivers/PCI/PCI.h | 7 +++++++ drivers/ethernet/Packet.h | 9 ++++++++- drivers/ethernet/RTL8139.c | 30 ++++++++++++++++++++++++++---- kernel/etc/Shell.c | 2 +- kernel/process/Process.c | 5 +++-- 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/drivers/PCI/PCI.c b/drivers/PCI/PCI.c index 07e0987..5393359 100644 --- a/drivers/PCI/PCI.c +++ b/drivers/PCI/PCI.c @@ -4,13 +4,6 @@ #include "Io.h" #include "stdint.h" -static PciDevice found_device; -static int device_found_flag; -static uint16_t target_vendor_id; -static uint16_t target_device_id; -// Callback function pointer type -typedef void (*PciDeviceCallback)(PciDevice device); - uint32_t PciConfigReadDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { uint32_t address; uint32_t lbus = (uint32_t)bus; diff --git a/drivers/PCI/PCI.h b/drivers/PCI/PCI.h index a1aed2b..851b241 100644 --- a/drivers/PCI/PCI.h +++ b/drivers/PCI/PCI.h @@ -15,6 +15,13 @@ typedef struct { uint8_t prog_if; // Programming Interface } PciDevice; +static PciDevice found_device; +static int device_found_flag; +static uint16_t target_vendor_id; +static uint16_t target_device_id; +// Callback function pointer type +typedef void (*PciDeviceCallback)(PciDevice device); + // Function prototypes void PciEnumerate(); int PciFindDevice(uint16_t vendor_id, uint16_t device_id, PciDevice* out_device); diff --git a/drivers/ethernet/Packet.h b/drivers/ethernet/Packet.h index 04c5e91..464ebb0 100644 --- a/drivers/ethernet/Packet.h +++ b/drivers/ethernet/Packet.h @@ -5,7 +5,11 @@ // Endianness conversion - crucial for network packets // Network byte order is Big Endian, x86 is Little Endian. -#define HTONS(n) ((((n) & 0xFF) << 8) | (((n) & 0xFF00) >> 8)) +static inline uint16_t bswap16(uint16_t v) { + return (uint16_t)((v << 8) | (v >> 8)); +} +#define HTONS(x) bswap16((uint16_t)(x)) +#define NTOHS(x) bswap16((uint16_t)(x)) // Ethernet Header (14 bytes) typedef struct { @@ -33,5 +37,8 @@ typedef struct { ArpPacket arp; } __attribute__((packed)) FullArpPacket; +_Static_assert(sizeof(EthernetHeader) == 14, "EthernetHeader must be 14 bytes"); +_Static_assert(sizeof(ArpPacket) == 28, "ArpPacket must be 28 bytes"); +_Static_assert(sizeof(FullArpPacket) == 42, "FullArpPacket must be 42 bytes"); #endif // PACKET_H \ No newline at end of file diff --git a/drivers/ethernet/RTL8139.c b/drivers/ethernet/RTL8139.c index bac5f5f..8951748 100644 --- a/drivers/ethernet/RTL8139.c +++ b/drivers/ethernet/RTL8139.c @@ -5,6 +5,7 @@ #include "Io.h" #include "KernelHeap.h" // For allocating memory #include "MemOps.h" +#include "VMem.h" // Global device object static Rtl8139Device rtl_device; @@ -19,8 +20,14 @@ void Rtl8139_Init() { PrintKernel("Found RTL8139!\n"); // --- Part 1: Read BAR0 and get the I/O base address --- - uint32_t bar0 = PciConfigReadDWord(rtl_device.pci_info.bus, rtl_device.pci_info.device, rtl_device.pci_info.function, 0x10); - rtl_device.io_base = bar0 & 0xFFFC; + const uint32_t bar0 = PciConfigReadDWord(rtl_device.pci_info.bus, rtl_device.pci_info.device, rtl_device.pci_info.function, 0x10); + if (bar0 & 0x1) { + // I/O mapped + rtl_device.io_base = bar0 & ~0x3; + } else { + PrintKernel("RTL8139 BAR0 is memory mapped, not supported.\n"); + return; + } PrintKernel("I/O Base: 0x"); PrintKernelHex(rtl_device.io_base); PrintKernel("\n"); // --- Part 2: Power on and Reset --- @@ -42,15 +49,30 @@ void Rtl8139_Init() { // NOTE: This MUST be physically contiguous memory! For now, we assume KernelMemoryAlloc does this. // In a real OS, you'd need a proper physical memory manager. rtl_device.rx_buffer = KernelMemoryAlloc(RX_BUFFER_SIZE); + if (!rtl_device.rx_buffer) { + PrintKernel("Failed to allocate RX buffer.\n"); + return; + } + for (int i = 0; i < TX_BUFFER_COUNT; i++) { rtl_device.tx_buffers[i] = KernelMemoryAlloc(2048); // 2K per TX buffer + if (!rtl_device.tx_buffers[i]) { + PrintKernel("Failed to allocate TX buffer.\n"); + // Clean up previously allocated buffers + for (int j = 0; j < i; j++) { + KernelFree(rtl_device.tx_buffers[j]); + } + KernelFree(rtl_device.rx_buffer); + return; + } } + rtl_device.current_tx_buffer = 0; PrintKernel("DMA buffers allocated.\n"); // --- Part 4: Tell the card where the receive buffer is --- // The hardware needs the PHYSICAL address of the buffer. - uint32_t rx_phys_addr = (uint32_t)rtl_device.rx_buffer; // Assuming identity mapping for now + uint32_t rx_phys_addr = VIRT_TO_PHYS(rtl_device.rx_buffer); // Assuming identity mapping for now outl(rtl_device.io_base + REG_RX_BUFFER_START, rx_phys_addr); PrintKernel("Receive buffer configured.\n"); @@ -61,7 +83,7 @@ void Rtl8139_Init() { // Configure Rx register: accept broadcast, multicast, and packets for our MAC (AB+AM+APM) // and wrap packets that are too long. - outl(rtl_device.io_base + REG_RX_CONFIG, 0x0F); + outl(rtl_device.io_base + REG_RX_CONFIG, (1 << 7) | (1 << 3) | (1 << 2) | (1 << 1)); PrintKernel("RTL8139 initialization finished!\n"); } diff --git a/kernel/etc/Shell.c b/kernel/etc/Shell.c index b42b2b8..869e088 100644 --- a/kernel/etc/Shell.c +++ b/kernel/etc/Shell.c @@ -81,7 +81,7 @@ void ArpRequestTestProcess() { // Get the network card's info, especially our MAC address const Rtl8139Device* nic = GetRtl8139Device(); if (!nic) { - // Handle error: NIC not initialized + PrintKernelError("[NIC] RTL8139 not ready"); return; } diff --git a/kernel/process/Process.c b/kernel/process/Process.c index d3227bc..1efdf63 100644 --- a/kernel/process/Process.c +++ b/kernel/process/Process.c @@ -259,8 +259,9 @@ void TerminateProcess(uint32_t pid, TerminationReason reason, uint32_t exit_code RequestSchedule(); } - AddToTerminationQueueAtomic(slot); - proc->state = PROC_ZOMBIE; + proc->state = PROC_ZOMBIE; // Set state FIRST + __sync_synchronize(); // Full memory barrier + AddToTerminationQueueAtomic(slot); // Then add to queue SpinLock(&pid_lock); int idx = proc->pid / 64; int bit = proc->pid % 64;