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
2 changes: 2 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ jobs:
grub-common \
qemu-system-x86 \
mtools \
lld \
llvm \

- name: Compile & Link
run: |
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*.krnl
*.krnlV
isodir
*.iso
.idea
Expand All @@ -10,3 +10,4 @@ target
.venv
*cache*
.amazonq
*backup
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ It would be amazing if you could contribute to this project!

## Prerequisites

- meson >= 1.0.0
- meson >= 1.4.0
- ninja >= 1.11
- clang >= 18.0.0 (or any C-compliant compiler)
- nasm >= 2.16
Expand All @@ -45,7 +45,6 @@ It would be amazing if you could contribute to this project!
```bash
git clone https://github.com/assembler-0/VoidFrame.git
cd VoidFrame
python scripts/vfconfig.py
meson setup build
cd build
ninja
Expand Down
Binary file modified drivers/Ide.c
Binary file not shown.
6 changes: 4 additions & 2 deletions drivers/Ide.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <stdint.h>

#include "BlockDevice.h"

// IDE Controller Ports
#define IDE_PRIMARY_BASE 0x1F0
#define IDE_SECONDARY_BASE 0x170
Expand Down Expand Up @@ -59,8 +61,8 @@ typedef struct {
// Core Functions
int IdeInit(void);
int IdeIsInitialized(void);
int IdeReadSector(uint8_t drive, uint32_t lba, void* buffer);
int IdeWriteSector(uint8_t drive, uint32_t lba, const uint8_t* buffer);
int IdeReadBlocks(BlockDevice* device, uint64_t start_lba, uint32_t count, void* buffer);
int IdeWriteBlocks(BlockDevice* device, uint64_t start_lba, uint32_t count, const void* buffer);
int IdeGetDriveInfo(uint8_t drive, char* model_out);
int IdeReadLBA2048(uint8_t drive, uint32_t lba, void* buffer);
int IdeIsAtapi(uint8_t drive);
Expand Down
92 changes: 92 additions & 0 deletions drivers/storage/AHCI.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "KernelHeap.h"
#include "MemOps.h"
#include "VMem.h"
#include "BlockDevice.h"
#include "Format.h"
#include "PCI/PCI.h"

#define FIS_TYPE_REG_H2D 0x27
#define ATA_CMD_READ_DMA_EX 0x25
Expand All @@ -12,6 +15,10 @@

static AHCIController g_ahci_controller = {0};

// Forward declarations
static int AHCI_ReadBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, void* buffer);
static int AHCI_WriteBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, const void* buffer);

static uint32_t AHCI_ReadReg(uint32_t offset) {
return *(volatile uint32_t*)(g_ahci_controller.mmio_base + offset);
}
Expand Down Expand Up @@ -215,6 +222,42 @@ static int AHCI_SendCommand(int port, uint8_t command, uint64_t lba, uint16_t co
return 0;
}

static uint64_t AHCI_GetDriveCapacity(int port) {
// Allocate buffer for IDENTIFY data
uint16_t* identify_data = (uint16_t*)KernelMemoryAlloc(512);
if (!identify_data) return 0;

// Send IDENTIFY command
int result = AHCI_SendCommand(port, ATA_CMD_IDENTIFY, 0, 1, identify_data, 0);
if (result != 0) {
KernelFree(identify_data);
return 0x1000000; // Fallback size (8GB)
}

// Get total sectors from IDENTIFY data
// For LBA48: words 100-103 contain total sectors
// For LBA28: words 60-61 contain total sectors
uint64_t total_sectors = 0;

// Check if LBA48 is supported (bit 10 of word 83)
if (identify_data[83] & (1 << 10)) {
// LBA48 - use words 100-103
total_sectors = *(uint64_t*)(identify_data + 100);
} else {
// LBA28 - use words 60-61
total_sectors = *(uint32_t*)(identify_data + 60);
}

KernelFree(identify_data);

// Sanity check
if (total_sectors == 0 || total_sectors > 0x1000000000ULL) {
return 0x1000000; // Fallback to 8GB
}

return total_sectors;
}

int AHCI_Init(void) {
PrintKernel("AHCI: Initializing AHCI driver...\n");

Expand Down Expand Up @@ -337,6 +380,38 @@ int AHCI_Init(void) {
PrintKernel("AHCI: Port ");
PrintKernelInt(i);
PrintKernel(" initialized successfully\n");

// Register as block device
char dev_name[16];
FormatA(dev_name, sizeof(dev_name), "sd%c", 'a' + i);

// Get actual sector count from IDENTIFY command
uint64_t total_sectors = AHCI_GetDriveCapacity(i);

PrintKernel("AHCI: Port ");
PrintKernelInt(i);
PrintKernel(" capacity: ");
PrintKernelInt(total_sectors);
PrintKernel(" sectors (");
PrintKernelInt((total_sectors * 512) / (1024 * 1024));
PrintKernel(" MB)\n");

BlockDevice* dev = BlockDeviceRegister(
DEVICE_TYPE_AHCI,
512,
total_sectors,
dev_name,
(void*)(uintptr_t)i, // Port number as driver data
(ReadBlocksFunc)AHCI_ReadBlocksWrapper,
(WriteBlocksFunc)AHCI_WriteBlocksWrapper
);

if (dev) {
PrintKernel("AHCI: Registered block device: ");
PrintKernel(dev_name);
PrintKernel("\n");
BlockDeviceDetectAndRegisterPartitions(dev);
}
}
}

Expand All @@ -363,4 +438,21 @@ int AHCI_WriteSectors(int port, uint64_t lba, uint16_t count, const void* buffer

const AHCIController* AHCI_GetController(void) {
return g_ahci_controller.initialized ? &g_ahci_controller : NULL;
}

// Wrapper functions for BlockDevice integration
static int AHCI_ReadBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, void* buffer) {
if (!device || !device->driver_data) return -1;
int port = (uintptr_t)device->driver_data;

// AHCI_ReadSectors expects sectors, not blocks, but they're the same for 512-byte sectors
return AHCI_ReadSectors(port, start_lba, count, buffer);
}

static int AHCI_WriteBlocksWrapper(struct BlockDevice* device, uint64_t start_lba, uint32_t count, const void* buffer) {
if (!device || !device->driver_data) return -1;
int port = (uintptr_t)device->driver_data;

// AHCI_WriteSectors expects sectors, not blocks, but they're the same for 512-byte sectors
return AHCI_WriteSectors(port, start_lba, count, buffer);
}
86 changes: 86 additions & 0 deletions fs/BlockDevice.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "BlockDevice.h"
#include "MBR.h"
#include "KernelHeap.h"
#include "StringOps.h"
#include "Console.h"

static BlockDevice g_block_devices[MAX_BLOCK_DEVICES];
static int g_next_device_id = 0;

void BlockDeviceInit() {
PrintKernel("BlockDevice: Initializing block device subsystem...\n");
for (int i = 0; i < MAX_BLOCK_DEVICES; i++) {
g_block_devices[i].active = false;
}
g_next_device_id = 0;
PrintKernel("BlockDevice: Block device table cleared\n");
}

BlockDevice* BlockDeviceRegister(BlockDeviceType type, uint32_t block_size, uint64_t total_blocks, const char* name, void* driver_data, ReadBlocksFunc read, WriteBlocksFunc write) {
PrintKernel("BlockDevice: Registering device '");
PrintKernel(name);
PrintKernel("' (type=");
PrintKernelInt(type);
PrintKernel(", blocks=");
PrintKernelInt(total_blocks);
PrintKernel(")\n");

if (g_next_device_id >= MAX_BLOCK_DEVICES) {
PrintKernel("BlockDevice: Maximum number of block devices reached\n");
return NULL; // No more space for new devices
}

int id = g_next_device_id++;
BlockDevice* dev = &g_block_devices[id];

dev->id = id;
dev->active = true;
dev->type = type;
dev->block_size = block_size;
dev->total_blocks = total_blocks;
FastStrCopy(dev->name, name, sizeof(dev->name) - 1);
dev->driver_data = driver_data;
dev->read_blocks = read;
dev->write_blocks = write;
dev->parent = NULL;
dev->lba_offset = 0;

PrintKernel("BlockDevice: Successfully registered '");
PrintKernel(name);
PrintKernel("' as device ID ");
PrintKernelInt(id);
PrintKernel("\n");

return dev;
}

BlockDevice* BlockDeviceGet(int id) {
if (id < 0 || id >= g_next_device_id || !g_block_devices[id].active) {
return NULL;
}
return &g_block_devices[id];
}

int BlockDeviceRead(int device_id, uint64_t start_lba, uint32_t count, void* buffer) {
BlockDevice* dev = BlockDeviceGet(device_id);
if (!dev || !dev->read_blocks) {
return -1;
}
return dev->read_blocks(dev, start_lba, count, buffer);
}

int BlockDeviceWrite(int device_id, uint64_t start_lba, uint32_t count, const void* buffer) {
BlockDevice* dev = BlockDeviceGet(device_id);
if (!dev || !dev->write_blocks) {
return -1;
}
return dev->write_blocks(dev, start_lba, count, buffer);
}

void BlockDeviceDetectAndRegisterPartitions(BlockDevice* drive) {
if (!drive || drive->type == DEVICE_TYPE_PARTITION) {
return; // Don't partition a partition
}

ParseMBR(drive);
}
48 changes: 48 additions & 0 deletions fs/BlockDevice.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include "stdint.h"
#include "stdbool.h"

#define MAX_BLOCK_DEVICES 16

typedef enum {
DEVICE_TYPE_UNKNOWN,
DEVICE_TYPE_IDE,
DEVICE_TYPE_AHCI,
DEVICE_TYPE_NVME,
DEVICE_TYPE_USB,
DEVICE_TYPE_VIRTIO,
DEVICE_TYPE_PARTITION
} BlockDeviceType;

struct BlockDevice;

typedef int (*ReadBlocksFunc)(struct BlockDevice* device, uint64_t start_lba, uint32_t count, void* buffer);
typedef int (*WriteBlocksFunc)(struct BlockDevice* device, uint64_t start_lba, uint32_t count, const void* buffer);

typedef struct BlockDevice {
int id;
bool active;
BlockDeviceType type;
uint32_t block_size;
uint64_t total_blocks;
char name[32];

// Driver-specific data
void* driver_data;

// Parent device (for partitions)
struct BlockDevice* parent;
uint64_t lba_offset; // for partitions

// Function pointers for I/O
ReadBlocksFunc read_blocks;
WriteBlocksFunc write_blocks;
} BlockDevice;

void BlockDeviceInit();
BlockDevice* BlockDeviceRegister(BlockDeviceType type, uint32_t block_size, uint64_t total_blocks, const char* name, void* driver_data, ReadBlocksFunc read, WriteBlocksFunc write);
BlockDevice* BlockDeviceGet(int id);
int BlockDeviceRead(int device_id, uint64_t start_lba, uint32_t count, void* buffer);
int BlockDeviceWrite(int device_id, uint64_t start_lba, uint32_t count, const void* buffer);
void BlockDeviceDetectAndRegisterPartitions(BlockDevice* drive);
Loading
Loading