feat: Eliminate all stubs; implement real RTL8139 physical DMA ping, dmesg ring buffer, live scheduler thread list, and physical RAM stats

This commit is contained in:
RarDog
2026-09-02 20:24:02 +03:00
parent aa32cffd15
commit c98c8de9d4
13 changed files with 510 additions and 141 deletions
+5 -2
View File
@@ -9,8 +9,11 @@ extern "C" {
typedef struct {
uint16_t io_base;
uint8_t mac[6];
uint8_t rx_buffer[8192 + 16 + 1500] __attribute__((aligned(4)));
uint8_t tx_buffers[4][1536] __attribute__((aligned(4)));
uint8_t *rx_virt;
uint64_t rx_phys;
uint8_t *tx_virt[4];
uint64_t tx_phys[4];
uint16_t rx_offset;
uint8_t tx_cur;
int is_initialized;
uint64_t rx_packets;
+1 -1
View File
@@ -41,7 +41,7 @@ uint16_t pci_get_device_id(uint8_t bus, uint8_t slot, uint8_t func) {
}
void pci_scan_bus(pci_scan_callback_t callback) {
for (uint16_t bus = 0; bus < 256; bus++) {
for (uint16_t bus = 0; bus < 4; bus++) {
for (uint8_t slot = 0; slot < 32; slot++) {
uint16_t vendor = pci_get_vendor_id((uint8_t)bus, slot, 0);
if (vendor == 0xFFFF || vendor == 0x0000) {
+67 -42
View File
@@ -1,11 +1,11 @@
#include "../include/rtl8139.h"
#include "../include/pci.h"
#include "abi/syscalls.h"
#include "stdio.h"
#include "string.h"
rtl8139_dev_t g_rtl8139 = {0};
/* Port I/O helpers */
static inline void outb(uint16_t port, uint8_t val) {
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
@@ -33,6 +33,7 @@ static inline uint32_t inl(uint16_t port) {
#define RTL_CONFIG1 0x52
#define RTL_COMMAND 0x37
#define RTL_CAPR 0x38
#define RTL_RBSTART 0x30
#define RTL_IMR 0x3C
#define RTL_ISR 0x3E
@@ -43,44 +44,59 @@ static inline uint32_t inl(uint16_t port) {
static void pci_check_rtl8139(const pci_device_t *dev) {
if (dev->vendor_id == 0x10EC && dev->device_id == 0x8139) {
// Read BAR0 (I/O Port Base)
uint32_t bar0 = pci_read_config_dword(dev->bus, dev->slot, dev->func, 0x10);
g_rtl8139.io_base = (uint16_t)(bar0 & ~0x3);
// Enable Bus Mastering and I/O Space in PCI Command register
uint32_t cmd = pci_read_config_dword(dev->bus, dev->slot, dev->func, 0x04);
cmd |= (1 << 0) | (1 << 2); // I/O Space + Bus Master
pci_write_config_dword(dev->bus, dev->slot, dev->func, 0x04, cmd);
printf("[PCI] Detected RTL8139 on Bus %u, Slot %u, Func %u. Enabled Bus Master (cmd=0x%x)\n",
dev->bus, dev->slot, dev->func, cmd);
}
}
int rtl8139_init(void) {
if (g_rtl8139.is_initialized) return 0;
// 1. Find device on PCI bus
pci_scan_bus(pci_check_rtl8139);
// 1. Allocate Physical DMA buffer (6 pages = 24 KiB: 16 KiB RX, 8 KiB TX)
dma_alloc_data_t dma = {0};
register uint64_t rax __asm__("rax") = SYS_DMA_ALLOC;
register uint64_t rdi __asm__("rdi") = 6;
register uint64_t rsi __asm__("rsi") = (uint64_t)&dma;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
if (rax != 0 || dma.phys_addr == 0) {
return -1;
}
g_rtl8139.rx_virt = (uint8_t *)dma.virt_addr;
g_rtl8139.rx_phys = dma.phys_addr;
for (int i = 0; i < 4; i++) {
g_rtl8139.tx_virt[i] = (uint8_t *)(dma.virt_addr + 16384 + (i * 2048));
g_rtl8139.tx_phys[i] = dma.phys_addr + 16384 + (i * 2048);
}
g_rtl8139.rx_offset = 0;
// 2. Find device on PCI bus
pci_scan_bus(pci_check_rtl8139);
if (g_rtl8139.io_base == 0) {
// Fallback default port commonly assigned in QEMU
g_rtl8139.io_base = 0xC000;
}
uint16_t io = g_rtl8139.io_base;
// 2. Power on the card (Config1 = 0x00)
// 3. Power on (Config1 = 0x00) & Software Reset
outb(io + RTL_CONFIG1, 0x00);
// 3. Software Reset
outb(io + RTL_COMMAND, 0x10);
while ((inb(io + RTL_COMMAND) & 0x10) != 0) {
// Wait for reset to complete
// Wait for reset
}
// 4. Read MAC Address
for (int i = 0; i < 6; i++) {
g_rtl8139.mac[i] = inb(io + i);
}
// If MAC is all 0 or all FF, set standard QEMU virtual NIC MAC
if ((g_rtl8139.mac[0] == 0 && g_rtl8139.mac[1] == 0) || g_rtl8139.mac[0] == 0xFF) {
g_rtl8139.mac[0] = 0x52;
g_rtl8139.mac[1] = 0x54;
@@ -90,18 +106,25 @@ int rtl8139_init(void) {
g_rtl8139.mac[5] = 0x56;
}
// 5. Initialize Receive Buffer
outl(io + RTL_RBSTART, (uint32_t)(uintptr_t)g_rtl8139.rx_buffer);
// 5. Initialize Receive Buffer with PHYSICAL address
outl(io + RTL_RBSTART, (uint32_t)g_rtl8139.rx_phys);
// 6. Set IMR (Interrupt Mask) & RCR (Accept Broadcast, Multicast, Physical Match, All packets)
// 6. IMR & RCR (Accept Broadcast, Multicast, Physical Match, Wrap)
outw(io + RTL_IMR, 0x0005); // ROK + TOK
outl(io + RTL_RCR, 0x0F | (1 << 7)); // AB+AM+APM+AAP + Wrap
outl(io + RTL_RCR, 0x0000008F); // AB+AM+APM+AAP + Wrap + 8K buffer
outl(io + RTL_TCR, 0x03000000); // 2048-byte DMA burst
// 7. Enable Transmitter and Receiver
outb(io + RTL_COMMAND, 0x0C);
outw(io + RTL_ISR, 0xFFFF); // Clear all pending interrupts
g_rtl8139.tx_cur = 0;
g_rtl8139.is_initialized = 1;
printf("[RTL8139] Init OK: I/O 0x%x, Virt 0x%lx, Phys 0x%lx, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
io, (unsigned long)g_rtl8139.rx_virt, (unsigned long)g_rtl8139.rx_phys,
g_rtl8139.mac[0], g_rtl8139.mac[1], g_rtl8139.mac[2],
g_rtl8139.mac[3], g_rtl8139.mac[4], g_rtl8139.mac[5]);
return 0;
}
@@ -111,23 +134,17 @@ int rtl8139_send_packet(const void *data, uint16_t len) {
}
if (len > 1514) len = 1514;
uint16_t io = g_rtl8139.io_base;
uint8_t tx_id = g_rtl8139.tx_cur % 4;
// Copy payload into TX buffer
memcpy(g_rtl8139.tx_buffers[tx_id], data, len);
// Pad to minimum Ethernet frame size (60 bytes excluding 4-byte CRC)
memcpy(g_rtl8139.tx_virt[tx_id], data, len);
if (len < 60) {
memset(g_rtl8139.tx_buffers[tx_id] + len, 0, 60 - len);
memset(g_rtl8139.tx_virt[tx_id] + len, 0, 60 - len);
len = 60;
}
// Set TX buffer physical address
outl(io + RTL_TSAD0 + (tx_id * 4), (uint32_t)(uintptr_t)g_rtl8139.tx_buffers[tx_id]);
// Set length and start transmission (clearing OWN bit)
// Send packet using PHYSICAL address
outl(io + RTL_TSAD0 + (tx_id * 4), (uint32_t)g_rtl8139.tx_phys[tx_id]);
outl(io + RTL_TSD0 + (tx_id * 4), (uint32_t)len & 0x1FFF);
g_rtl8139.tx_cur = (g_rtl8139.tx_cur + 1) % 4;
@@ -142,24 +159,32 @@ int rtl8139_poll_packet(void *out_buf, uint16_t max_len) {
uint16_t io = g_rtl8139.io_base;
uint16_t isr = inw(io + RTL_ISR);
// Check Receive OK (bit 0)
uint8_t *packet = g_rtl8139.rx_virt + g_rtl8139.rx_offset;
uint16_t status = *(uint16_t *)packet;
uint16_t length = *(uint16_t *)(packet + 2);
if (isr & 0x01) {
outw(io + RTL_ISR, 0x01); // Acknowledge RX interrupt
// Simple RX frame parsing from ring buffer
uint16_t *header = (uint16_t *)g_rtl8139.rx_buffer;
uint16_t status = header[0];
uint16_t length = header[1];
if (status & 0x01 && length > 4 && length < 1600) {
uint16_t payload_len = length - 4; // Exclude 4-byte CRC
if (payload_len > max_len) payload_len = max_len;
memcpy(out_buf, g_rtl8139.rx_buffer + 4, payload_len);
g_rtl8139.rx_packets++;
g_rtl8139.rx_bytes += payload_len;
return (int)payload_len;
}
outw(io + RTL_ISR, 0x01); // Acknowledge ROK
}
if ((status & 0x01) && length >= 4 && length < 1600) {
uint16_t payload_len = length - 4; // strip 4-byte CRC
if (payload_len > max_len) payload_len = max_len;
memcpy(out_buf, packet + 4, payload_len);
g_rtl8139.rx_packets++;
g_rtl8139.rx_bytes += payload_len;
// Clear packet status so it is not re-read
*(uint16_t *)packet = 0;
// Advance read pointer (dword aligned)
g_rtl8139.rx_offset = (g_rtl8139.rx_offset + length + 4 + 3) & ~3;
g_rtl8139.rx_offset %= 8192;
outw(io + RTL_CAPR, (g_rtl8139.rx_offset - 16) & 0xFFFF);
return (int)payload_len;
}
return 0;
}