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
4 changes: 1 addition & 3 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
name: VoidFrame kernel build

on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main ]
branches: [ main, dev ]
release:
types: [created]

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ It would be amazing if you could contribute to this project!
```bash
git clone https://github.com/assembler-0/VoidFrame.git
cd VoidFrame
python vfconfig.py
python scripts/vfconfig.py
meson setup build
cd build
ninja
Expand Down
152 changes: 123 additions & 29 deletions drivers/virtio/VirtioBlk.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "PCI/PCI.h"
#include "VMem.h"
#include "stdbool.h"

#include "Virtio.h"
// Globals to hold the capability structures we find
static volatile int* virtio_lock;
static struct VirtioPciCap cap_common_cfg;
Expand All @@ -21,6 +21,18 @@ static struct VirtqAvail* vq_avail_ring;
static struct VirtqUsed* vq_used_ring;
static uint16_t vq_size;
static uint16_t vq_next_desc_idx = 0;
static uint16_t last_used_idx = 0;

// A structure to keep track of pending requests
struct VirtioBlkRequest {
struct VirtioBlkReq* req_hdr;
uint8_t* status;
};

// Let's assume a maximum of 128 pending requests
#define MAX_PENDING_REQS 128
static struct VirtioBlkRequest pending_reqs[MAX_PENDING_REQS];

volatile struct VirtioPciCommonCfg* common_cfg_ptr;

void ReadVirtioCapability(PciDevice device, uint8_t cap_offset, struct VirtioPciCap* cap) {
Expand Down Expand Up @@ -188,65 +200,147 @@ void InitializeVirtioBlk(PciDevice device) {
// Enable the queue
common_cfg_ptr->queue_enable = 1;

// Initialize the pending requests array
for (int i = 0; i < MAX_PENDING_REQS; ++i) {
pending_reqs[i].req_hdr = NULL;
pending_reqs[i].status = NULL;
}

PrintKernel("VirtIO-Blk: Driver initialized successfully!\n");
}

int VirtioBlkRead(uint64_t sector, void* buffer) {
// Add synchronization for concurrent access
SpinLock(virtio_lock);
// Check if we have enough descriptors available
SpinLock(&virtio_lock);

if ((vq_next_desc_idx + 3) > vq_size) {
PrintKernel("VirtIO-Blk: Error - Not enough descriptors available\n");
// SpinUnlock(&virtio_lock);
SpinUnlock(&virtio_lock);
return -1;
}
// Step 1: Allocate request header and status byte

struct VirtioBlkReq* req_hdr = VMemAlloc(sizeof(struct VirtioBlkReq));
uint8_t* status = VMemAlloc(sizeof(uint8_t));
if (!req_hdr || !status) {
PrintKernel("VirtIO-Blk: Failed to allocate request header/status\n");
if (req_hdr) VMemFree(req_hdr, sizeof(struct VirtioBlkReq));
if (status) VMemFree(status, sizeof(uint8_t));
// SpinUnlock(&virtio_lock);
return -1; // Error
SpinUnlock(&virtio_lock);
return -1;
}
// Step 2: Fill out the request header

req_hdr->type = VIRTIO_BLK_T_IN;
req_hdr->reserved = 0;
req_hdr->sector = sector;
// Step 3: Set up the descriptor chain

uint16_t head_idx = vq_next_desc_idx;
// Descriptor 1: Request Header (Driver -> Device)
vq_desc_table[head_idx].addr = VIRT_TO_PHYS((uint64_t)req_hdr);
vq_desc_table[head_idx].len = sizeof(struct VirtioBlkReq);
vq_desc_table[head_idx].flags = VIRTQ_DESC_F_NEXT;
vq_desc_table[head_idx].next = head_idx + 1;
// Descriptor 2: Data Buffer (Device -> Driver)

vq_desc_table[head_idx + 1].addr = VIRT_TO_PHYS((uint64_t)buffer);
vq_desc_table[head_idx + 1].len = 512; // Assume 512-byte sectors
vq_desc_table[head_idx + 1].len = 512;
vq_desc_table[head_idx + 1].flags = VIRTQ_DESC_F_WRITE | VIRTQ_DESC_F_NEXT;
vq_desc_table[head_idx + 1].next = head_idx + 2;
// Descriptor 3: Status (Device -> Driver)

vq_desc_table[head_idx + 2].addr = VIRT_TO_PHYS((uint64_t)status);
vq_desc_table[head_idx + 2].len = sizeof(uint8_t);
vq_desc_table[head_idx + 2].flags = VIRTQ_DESC_F_WRITE;
vq_desc_table[head_idx + 2].next = 0; // End of chain
// Step 4: Add the chain to the available ring
vq_desc_table[head_idx + 2].next = 0;

pending_reqs[head_idx].req_hdr = req_hdr;
pending_reqs[head_idx].status = status;

vq_avail_ring->ring[vq_avail_ring->idx % vq_size] = head_idx;
// Step 5: Update the available ring index atomically
AtomicInc(&vq_avail_ring->idx);
// Step 6: Notify the device

vq_next_desc_idx = (vq_next_desc_idx + 3) % vq_size;

if (notify_ptr) {
*(notify_ptr + common_cfg_ptr->queue_notify_off) = 0; // Queue index is 0
*(notify_ptr + common_cfg_ptr->queue_notify_off) = 0;
}
// For now, we just update our internal descriptor index

while (last_used_idx != vq_used_ring->idx) {
struct VirtqUsedElem* used_elem = &vq_used_ring->ring[last_used_idx % vq_size];
uint32_t used_desc_id = used_elem->id;

VMemFree(pending_reqs[used_desc_id].req_hdr, sizeof(struct VirtioBlkReq));
VMemFree(pending_reqs[used_desc_id].status, sizeof(uint8_t));

pending_reqs[used_desc_id].req_hdr = NULL;
pending_reqs[used_desc_id].status = NULL;

last_used_idx++;
}

SpinUnlock(&virtio_lock);
return 0;
}

int VirtioBlkWrite(uint64_t sector, void* buffer) {
SpinLock(&virtio_lock);

if ((vq_next_desc_idx + 3) > vq_size) {
PrintKernel("VirtIO-Blk: Error - Not enough descriptors available\n");
SpinUnlock(&virtio_lock);
return -1;
}

struct VirtioBlkReq* req_hdr = VMemAlloc(sizeof(struct VirtioBlkReq));
uint8_t* status = VMemAlloc(sizeof(uint8_t));
if (!req_hdr || !status) {
PrintKernel("VirtIO-Blk: Failed to allocate request header/status\n");
if (req_hdr) VMemFree(req_hdr, sizeof(struct VirtioBlkReq));
if (status) VMemFree(status, sizeof(uint8_t));
SpinUnlock(&virtio_lock);
return -1;
}

req_hdr->type = VIRTIO_BLK_T_OUT;
req_hdr->reserved = 0;
req_hdr->sector = sector;

uint16_t head_idx = vq_next_desc_idx;
vq_desc_table[head_idx].addr = VIRT_TO_PHYS((uint64_t)req_hdr);
vq_desc_table[head_idx].len = sizeof(struct VirtioBlkReq);
vq_desc_table[head_idx].flags = VIRTQ_DESC_F_NEXT;
vq_desc_table[head_idx].next = head_idx + 1;

vq_desc_table[head_idx + 1].addr = VIRT_TO_PHYS((uint64_t)buffer);
vq_desc_table[head_idx + 1].len = 512;
vq_desc_table[head_idx + 1].flags = VIRTQ_DESC_F_NEXT;
vq_desc_table[head_idx + 1].next = head_idx + 2;

vq_desc_table[head_idx + 2].addr = VIRT_TO_PHYS((uint64_t)status);
vq_desc_table[head_idx + 2].len = sizeof(uint8_t);
vq_desc_table[head_idx + 2].flags = VIRTQ_DESC_F_WRITE;
vq_desc_table[head_idx + 2].next = 0;

pending_reqs[head_idx].req_hdr = req_hdr;
pending_reqs[head_idx].status = status;

vq_avail_ring->ring[vq_avail_ring->idx % vq_size] = head_idx;
AtomicInc(&vq_avail_ring->idx);

vq_next_desc_idx = (vq_next_desc_idx + 3) % vq_size;
// TODO: Implement proper completion waiting mechanism
// This is critical for correctness
// For now, add a delay to allow completion (not production-ready)
// In production, use interrupts or polling with timeout
// Don't free these until after checking completion!
// These will need to be tracked and freed after the I/O completes
SpinUnlock(virtio_lock);
return 0; // Success (for now)
}

if (notify_ptr) {
*(notify_ptr + common_cfg_ptr->queue_notify_off) = 0;
}

while (last_used_idx != vq_used_ring->idx) {
struct VirtqUsedElem* used_elem = &vq_used_ring->ring[last_used_idx % vq_size];
uint32_t used_desc_id = used_elem->id;

VMemFree(pending_reqs[used_desc_id].req_hdr, sizeof(struct VirtioBlkReq));
VMemFree(pending_reqs[used_desc_id].status, sizeof(uint8_t));

pending_reqs[used_desc_id].req_hdr = NULL;
pending_reqs[used_desc_id].status = NULL;

last_used_idx++;
}

SpinUnlock(&virtio_lock);
return 0;
}
5 changes: 1 addition & 4 deletions drivers/virtio/VirtioBlk.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#ifndef VOIDFRAME_VIRTIOBLK_H
#define VOIDFRAME_VIRTIOBLK_H

#include "Virtio.h"
#include "PCI/PCI.h"

// VirtIO Block device specific definitions and function prototypes.

void InitializeVirtioBlk(PciDevice device);
int VirtioBlkRead(uint64_t sector, void* buffer);

int VirtioBlkWrite(uint64_t sector, void* buffer);
#endif //VOIDFRAME_VIRTIOBLK_H
Loading