Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ meson setup build
cd build
ninja
ninja img
ninja virtio-img
ninja extra-img
ninja run
```
#### Minimal setup
Expand Down Expand Up @@ -135,8 +135,10 @@ ninja runmin
### Drivers
- Network
- [x] RTL8139 (PCI)
- [x] E1000 (PCI)
- Sound
- [x] SB16 (PCI)
- [x] Generic PC speaker
- USB
- [x] xHCI
- VirtIO
Expand All @@ -159,4 +161,5 @@ ninja runmin
- [x] LPT
- Storage
- [x] PATA (IDE)
- [x] VirtIO Block
- [x] VirtIO Block
- [x] AHCI
5 changes: 4 additions & 1 deletion drivers/ISA/ISA.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,11 @@ void IsaAutoDetect(void) {
}

if (SB16_Probe(SB16_DSP_BASE)) {
IsaRegisterDevice(SB16_DSP_BASE, 16, 5, ISA_DMA_SB_8BIT,
IsaRegisterDevice(SB16_DSP_BASE, 16, 5, 1,
ISA_DEVICE_SOUND, "Sound Blaster 16");
PrintKernelSuccess("ISA: Sound Blaster 16 detected and registered\n");
} else {
PrintKernel("ISA: Sound Blaster 16 not detected\n");
}

}
Expand Down
19 changes: 19 additions & 0 deletions drivers/PCI/PCI.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ uint32_t PciConfigReadDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t off
return inl(0xCFC);
}

uint16_t PciReadConfig16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t dword = PciConfigReadDWord(bus, slot, func, offset & 0xFC);
return (dword >> ((offset & 2) * 8)) & 0xFFFF;
}

uint8_t PciConfigReadByte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t dword = PciConfigReadDWord(bus, slot, func, offset & 0xFC);
return (dword >> ((offset & 3) * 8)) & 0xFF;
Expand All @@ -47,6 +52,17 @@ void PciConfigWriteDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset
outl(0xCFC, data);
}

void PciWriteConfig16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t data) {
uint32_t dword_offset = offset & 0xFC;
uint32_t word_offset = offset & 0x02;

uint32_t current_value = PciConfigReadDWord(bus, slot, func, dword_offset);
uint32_t mask = ~(0xFFFF << (word_offset * 8));
uint32_t new_value = (current_value & mask) | ((uint32_t)data << (word_offset * 8));

PciConfigWriteDWord(bus, slot, func, dword_offset, new_value);
}

void PciConfigWriteByte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t data) {
// For byte writes, we need to read-modify-write the dword
uint32_t dword_offset = offset & 0xFC;
Expand Down Expand Up @@ -85,6 +101,9 @@ static void PciScanBus(PciDeviceCallback callback) {
pci_dev.class_code = (class_reg >> 24) & 0xFF;
pci_dev.subclass = (class_reg >> 16) & 0xFF;
pci_dev.prog_if = (class_reg >> 8) & 0xFF;

// Read BAR0
pci_dev.bar0 = PciConfigReadDWord(bus, device, func, 0x10);

// Call the provided callback with the device info
callback(pci_dev);
Expand Down
3 changes: 3 additions & 0 deletions drivers/PCI/PCI.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ typedef struct {
uint8_t class_code;
uint8_t subclass;
uint8_t prog_if; // Programming Interface
uint32_t bar0;
} PciDevice;

static PciDevice found_device;
Expand All @@ -34,8 +35,10 @@ void PciEnumerate();
int PciFindDevice(uint16_t vendor_id, uint16_t device_id, PciDevice* out_device);
int PciFindByClass(uint8_t class, uint8_t subclass, uint8_t prog_if, PciDevice* out_device);
uint32_t PciConfigReadDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
uint16_t PciReadConfig16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
uint8_t PciConfigReadByte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
void PciConfigWriteDWord(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t data);
void PciWriteConfig16(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t data);
void PciConfigWriteByte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t data);
uint64_t GetPCIMMIOSize(const PciDevice* pci_dev, uint32_t bar_value);
#endif // PCI_H
188 changes: 188 additions & 0 deletions drivers/ethernet/intel/E1000.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "E1000.h"
#include "Console.h"
#include "Cpu.h"
#include "Io.h"
#include "KernelHeap.h"
#include "MemOps.h"
#include "PCI/PCI.h"
#include "PMem.h"

static E1000Device g_e1000_device = {0};

static uint32_t E1000_ReadReg(uint32_t reg) {
return *(volatile uint32_t*)(g_e1000_device.mmio_base + reg);
}

static void E1000_WriteReg(uint32_t reg, uint32_t value) {
*(volatile uint32_t*)(g_e1000_device.mmio_base + reg) = value;
}

static uint16_t E1000_ReadEEPROM(uint8_t addr) {
E1000_WriteReg(E1000_EERD, (addr << 8) | 1);
uint32_t val;
do {
val = E1000_ReadReg(E1000_EERD);
} while (!(val & (1 << 4)));
return (val >> 16) & 0xFFFF;
}

static void E1000_ReadMAC(void) {
uint16_t mac01 = E1000_ReadEEPROM(0);
uint16_t mac23 = E1000_ReadEEPROM(1);
uint16_t mac45 = E1000_ReadEEPROM(2);

g_e1000_device.mac_address[0] = mac01 & 0xFF;
g_e1000_device.mac_address[1] = (mac01 >> 8) & 0xFF;
g_e1000_device.mac_address[2] = mac23 & 0xFF;
g_e1000_device.mac_address[3] = (mac23 >> 8) & 0xFF;
g_e1000_device.mac_address[4] = mac45 & 0xFF;
g_e1000_device.mac_address[5] = (mac45 >> 8) & 0xFF;
}

static void E1000_InitRX(void) {
// Allocate RX descriptors
g_e1000_device.rx_descs = (E1000RxDesc*)KernelMemoryAlloc(sizeof(E1000RxDesc) * E1000_NUM_RX_DESC);
g_e1000_device.rx_buffers = (uint8_t**)KernelMemoryAlloc(sizeof(uint8_t*) * E1000_NUM_RX_DESC);

// Allocate RX buffers
for (int i = 0; i < E1000_NUM_RX_DESC; i++) {
g_e1000_device.rx_buffers[i] = (uint8_t*)KernelMemoryAlloc(2048);
g_e1000_device.rx_descs[i].addr = (uint64_t)g_e1000_device.rx_buffers[i];
g_e1000_device.rx_descs[i].status = 0;
}

// Set RX descriptor base and length
uint64_t rx_desc_phys = (uint64_t)g_e1000_device.rx_descs;
E1000_WriteReg(E1000_RDBAL, rx_desc_phys & 0xFFFFFFFF);
E1000_WriteReg(E1000_RDBAH, (rx_desc_phys >> 32) & 0xFFFFFFFF);
E1000_WriteReg(E1000_RDLEN, E1000_NUM_RX_DESC * sizeof(E1000RxDesc));

// Set RX head and tail
E1000_WriteReg(E1000_RDH, 0);
E1000_WriteReg(E1000_RDT, E1000_NUM_RX_DESC - 1);

g_e1000_device.rx_cur = 0;

// Enable RX
E1000_WriteReg(E1000_RCTL, E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_BSIZE_2048);
}

static void E1000_InitTX(void) {
// Allocate TX descriptors
g_e1000_device.tx_descs = (E1000TxDesc*)KernelMemoryAlloc(sizeof(E1000TxDesc) * E1000_NUM_TX_DESC);
g_e1000_device.tx_buffers = (uint8_t**)KernelMemoryAlloc(sizeof(uint8_t*) * E1000_NUM_TX_DESC);

// Allocate TX buffers
for (int i = 0; i < E1000_NUM_TX_DESC; i++) {
g_e1000_device.tx_buffers[i] = (uint8_t*)KernelMemoryAlloc(2048);
g_e1000_device.tx_descs[i].addr = (uint64_t)g_e1000_device.tx_buffers[i];
g_e1000_device.tx_descs[i].status = 1; // DD bit set
}

// Set TX descriptor base and length
uint64_t tx_desc_phys = (uint64_t)g_e1000_device.tx_descs;
E1000_WriteReg(E1000_TDBAL, tx_desc_phys & 0xFFFFFFFF);
E1000_WriteReg(E1000_TDBAH, (tx_desc_phys >> 32) & 0xFFFFFFFF);
E1000_WriteReg(E1000_TDLEN, E1000_NUM_TX_DESC * sizeof(E1000TxDesc));

// Set TX head and tail
E1000_WriteReg(E1000_TDH, 0);
E1000_WriteReg(E1000_TDT, 0);

g_e1000_device.tx_cur = 0;

// Enable TX
E1000_WriteReg(E1000_TCTL, E1000_TCTL_EN | E1000_TCTL_PSP);
}

int E1000_Init(void) {

// Find E1000 device
PciDevice pci_dev;
if (PciFindDevice(E1000_VENDOR_ID, E1000_DEVICE_ID, &pci_dev) != 0) {
PrintKernel("E1000: Device not found\n");
return -1;
}

PrintKernel("E1000: Found device at ");
PrintKernelInt(pci_dev.bus);
PrintKernel(":");
PrintKernelInt(pci_dev.device);
PrintKernel(":");
PrintKernelInt(pci_dev.function);
PrintKernel("\n");

// Get MMIO base address
g_e1000_device.mmio_base = pci_dev.bar0 & ~0xF;

// Enable bus mastering
uint16_t cmd = PciReadConfig16(pci_dev.bus, pci_dev.device, pci_dev.function, 0x04);
PciWriteConfig16(pci_dev.bus, pci_dev.device, pci_dev.function, 0x04, cmd | 0x04);

// Reset device
E1000_WriteReg(E1000_CTRL, E1000_CTRL_RST);
delay(10000);

// Read MAC address
E1000_ReadMAC();
PrintKernel("E1000: MAC Address: ");
for (int i = 0; i < 6; i++) {
PrintKernelHex(g_e1000_device.mac_address[i]);
if (i < 5) PrintKernel(":");
}
PrintKernel("\n");

// Set MAC address in RAL/RAH
uint32_t ral = g_e1000_device.mac_address[0] |
(g_e1000_device.mac_address[1] << 8) |
(g_e1000_device.mac_address[2] << 16) |
(g_e1000_device.mac_address[3] << 24);
uint32_t rah = g_e1000_device.mac_address[4] |
(g_e1000_device.mac_address[5] << 8) |
(1 << 31); // Address Valid bit

E1000_WriteReg(E1000_RAL, ral);
E1000_WriteReg(E1000_RAH, rah);

// Initialize RX and TX
E1000_InitRX();
E1000_InitTX();

// Link up
E1000_WriteReg(E1000_CTRL, E1000_CTRL_SLU | E1000_CTRL_ASDE);

g_e1000_device.initialized = 1;
PrintKernelSuccess("E1000: Driver initialized successfully\n");

return 0;
}

int E1000_SendPacket(const void* data, uint16_t length) {
if (!g_e1000_device.initialized || length > 1518) {
return -1;
}

// Wait for descriptor to be available
while (!(g_e1000_device.tx_descs[g_e1000_device.tx_cur].status & 1)) {
// Descriptor not ready
}

// Copy data to buffer
FastMemcpy(g_e1000_device.tx_buffers[g_e1000_device.tx_cur], data, length);

// Set up descriptor
g_e1000_device.tx_descs[g_e1000_device.tx_cur].length = length;
g_e1000_device.tx_descs[g_e1000_device.tx_cur].cmd = (1 << 3) | (1 << 1) | 1; // RS | IFCS | EOP
g_e1000_device.tx_descs[g_e1000_device.tx_cur].status = 0;

// Update tail pointer
uint16_t old_cur = g_e1000_device.tx_cur;
g_e1000_device.tx_cur = (g_e1000_device.tx_cur + 1) % E1000_NUM_TX_DESC;
E1000_WriteReg(E1000_TDT, g_e1000_device.tx_cur);

return 0;
}

const E1000Device* E1000_GetDevice(void) {
return g_e1000_device.initialized ? &g_e1000_device : NULL;
}
90 changes: 90 additions & 0 deletions drivers/ethernet/intel/E1000.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#ifndef VOIDFRAME_E1000_H
#define VOIDFRAME_E1000_H

#include "stdint.h"

// E1000 PCI IDs
#define E1000_VENDOR_ID 0x8086
#define E1000_DEVICE_ID 0x100E // 82540EM

// Register offsets
#define E1000_CTRL 0x0000 // Device Control
#define E1000_STATUS 0x0008 // Device Status
#define E1000_EECD 0x0010 // EEPROM Control
#define E1000_EERD 0x0014 // EEPROM Read
#define E1000_ICR 0x00C0 // Interrupt Cause Read
#define E1000_IMS 0x00D0 // Interrupt Mask Set
#define E1000_IMC 0x00D8 // Interrupt Mask Clear
#define E1000_RCTL 0x0100 // RX Control
#define E1000_RDBAL 0x2800 // RX Descriptor Base Address Low
#define E1000_RDBAH 0x2804 // RX Descriptor Base Address High
#define E1000_RDLEN 0x2808 // RX Descriptor Length
#define E1000_RDH 0x2810 // RX Descriptor Head
#define E1000_RDT 0x2818 // RX Descriptor Tail
#define E1000_TCTL 0x0400 // TX Control
#define E1000_TDBAL 0x3800 // TX Descriptor Base Address Low
#define E1000_TDBAH 0x3804 // TX Descriptor Base Address High
#define E1000_TDLEN 0x3808 // TX Descriptor Length
#define E1000_TDH 0x3810 // TX Descriptor Head
#define E1000_TDT 0x3818 // TX Descriptor Tail
#define E1000_RAL 0x5400 // Receive Address Low
#define E1000_RAH 0x5404 // Receive Address High

// Control Register bits
#define E1000_CTRL_RST (1 << 26) // Device Reset
#define E1000_CTRL_ASDE (1 << 5) // Auto-Speed Detection Enable
#define E1000_CTRL_SLU (1 << 6) // Set Link Up

// RX Control bits
#define E1000_RCTL_EN (1 << 1) // Receiver Enable
#define E1000_RCTL_BAM (1 << 15) // Broadcast Accept Mode
#define E1000_RCTL_BSIZE_2048 (0 << 16) // Buffer Size 2048

// TX Control bits
#define E1000_TCTL_EN (1 << 1) // Transmitter Enable
#define E1000_TCTL_PSP (1 << 3) // Pad Short Packets

// Descriptor counts
#define E1000_NUM_RX_DESC 32
#define E1000_NUM_TX_DESC 32

// RX Descriptor
typedef struct {
uint64_t addr;
uint16_t length;
uint16_t checksum;
uint8_t status;
uint8_t errors;
uint16_t special;
} __attribute__((packed)) E1000RxDesc;

// TX Descriptor
typedef struct {
uint64_t addr;
uint16_t length;
uint8_t cso;
uint8_t cmd;
uint8_t status;
uint8_t css;
uint16_t special;
} __attribute__((packed)) E1000TxDesc;

// Device structure
typedef struct {
uint32_t mmio_base;
uint8_t mac_address[6];
E1000RxDesc* rx_descs;
E1000TxDesc* tx_descs;
uint8_t** rx_buffers;
uint8_t** tx_buffers;
uint16_t rx_cur;
uint16_t tx_cur;
int initialized;
} E1000Device;

// Function prototypes
int E1000_Init(void);
int E1000_SendPacket(const void* data, uint16_t length);
const E1000Device* E1000_GetDevice(void);

#endif // VOIDFRAME_E1000_H
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "RTL8139.h"
#include "../../mm/KernelHeap.h"
#include "../../mm/MemOps.h"
#include "../../mm/VMem.h"
#include "../../../mm/KernelHeap.h"
#include "../../../mm/MemOps.h"
#include "../../../mm/VMem.h"
#include "Console.h"
#include "Io.h"

Expand Down
File renamed without changes.
Loading