Skip to content
This repository was archived by the owner on Jan 4, 2026. It is now read-only.
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: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ add_custom_target(extra-img
COMMAND ${QEMU_IMG} create -f raw VirtioDisk.img 128M
COMMAND ${MKFS_EXT2} VirtioDisk.img
COMMAND ${QEMU_IMG} create -f raw SataDisk.img 128M
COMMAND ${MKFS_EXT2} SataDisk.img
COMMAND ${MKFS_FAT} -F12 SataDisk.img
COMMAND ${QEMU_IMG} create -f raw NVMeDisk.img 256M
COMMAND ${MKFS_EXT2} NVMeDisk.img
COMMENT "Creating extra disk images"
Expand Down
19 changes: 3 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# [VoidFrame] - a ring 0 kernel 💫

> A fast, simple, secure 64-bit ring-0 kernel written in C and assembly. With modern capabilities.
> A fast, simple, secure 64-bit ring-0 kernel written in C (Rust) and assembly. With modern capabilities.

---

- How it works: [here!](docs/ARCHITECTURE.md)
- How it works (outdated): [here!](docs/ARCHITECTURE.md)
- Development Guide: [here!](docs/DEVELOPMENT.md)

---
Expand All @@ -28,7 +28,6 @@ It would be amazing if you could contribute to this project!
- x64-compatible cpu (used: Intel i3-12100F)
- POSIX-compliant OS (SysV ABI) (used: Arch Linux 6.16.9-arch1-1)
- cmake >= 3.20 (used: cmake 4.1.2)
- meson >= 1.4 (used: meson 1.9.1)
- ninja >= 1.11 (used: ninja 1.21.1)
- clang/++ >= 18.0.0 (used: 20.1.8)
- rustup (nightly, bare metal toolchain) >= 1.89.0 (used: 1.92.0-nightly)
Expand All @@ -40,18 +39,6 @@ It would be amazing if you could contribute to this project!
- Note: depending on your distro, grub-mkrescue may require xorriso and mtools packages.

### Quickstart
#### Full development setup
```bash
# Meson
git clone https://github.com/assembler-0/VoidFrame.git
cd VoidFrame
meson setup build
cd build
ninja -j$(nproc)
ninja img
ninja extra-img
ninja run
```
```bash
# CMake
git clone https://github.com/assembler-0/VoidFrame.git
Expand All @@ -61,7 +48,7 @@ cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/linux-x64.cmake \
-G Ninja \
-DVF_SCHEDULER=<MLFQ/EEVDF>
-DVF_SCHEDULER=EEVDF
ccmake . # Optinal, tune as needed
ninja -j$(nproc)
ninja run
Expand Down
171 changes: 85 additions & 86 deletions drivers/ACPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#include "Console.h"
#include "Io.h"
#include "MemOps.h"
#include "Scheduler.h"
#include "StringOps.h"
#include "VMem.h"
#include "TSC.h"
#include "VFS.h"

static ACPIFADT* g_fadt = NULL;
static bool g_acpi_initialized = false;
Expand Down Expand Up @@ -47,128 +49,126 @@ static bool ValidateChecksum(void* table, uint32_t length) {

// Map ACPI table to virtual memory
static void* MapACPITable(uint32_t phys_addr, uint32_t size) {
// Align to page boundaries
uint32_t aligned_addr = phys_addr & ~0xFFF;
uint32_t offset = phys_addr - aligned_addr;
uint32_t aligned_size = ((size + offset + 0xFFF) & ~0xFFF);

uint64_t aligned_addr = phys_addr & ~0xFFF;
uint64_t offset = phys_addr - aligned_addr;
uint64_t aligned_size = ((size + offset + 0xFFF) & ~0xFFF);

void* virt_addr = VMemAlloc(aligned_size);
if (!virt_addr) return NULL;

if (!virt_addr) {
PrintKernelError("ACPI: Failed to allocate virtual memory for ACPI table\n");
return NULL;
}

if (VMemUnmap((uint64_t)virt_addr, aligned_size) != VMEM_SUCCESS) {
VMemFree(virt_addr, aligned_size);
PrintKernelError("ACPI: Failed to unmap virtual memory for ACPI table\n");
return NULL;
}

if (VMemMapMMIO((uint64_t)virt_addr, aligned_addr, aligned_size, PAGE_WRITABLE | PAGE_NOCACHE) != VMEM_SUCCESS) {
VMemFree(virt_addr, aligned_size);
// No need to free here as VMemMapMMIO should handle cleanup on failure
PrintKernelError("ACPI: Failed to map MMIO for ACPI table\n");
return NULL;
}

return (uint8_t*)virt_addr + offset;
}

static ACPIRSDT* g_rsdt = NULL;

void* AcpiFindTable(const char* signature) {
if (!g_rsdt) {
return NULL;
}

uint32_t entries = (g_rsdt->header.length - sizeof(ACPISDTHeader)) / 4;
for (uint32_t i = 0; i < entries; i++) {
ACPISDTHeader* header = (ACPISDTHeader*)MapACPITable(g_rsdt->table_pointers[i], sizeof(ACPISDTHeader));
if (!header) {
continue;
}

if (FastMemcmp(header->signature, signature, 4) == 0) {
void* table = MapACPITable(g_rsdt->table_pointers[i], header->length);
VMemUnmap((uint64_t)header - (g_rsdt->table_pointers[i] & 0xFFF), ((sizeof(ACPISDTHeader) + (g_rsdt->table_pointers[i] & 0xFFF) + 0xFFF) & ~0xFFF));
return table;
}

VMemUnmap((uint64_t)header - (g_rsdt->table_pointers[i] & 0xFFF), ((sizeof(ACPISDTHeader) + (g_rsdt->table_pointers[i] & 0xFFF) + 0xFFF) & ~0xFFF));
}

return NULL;
}

bool ACPIInit(void) {
PrintKernel("ACPI: Initializing ACPI subsystem...\n");

// Find RSDP

ACPIRSDPv1* rsdp = FindRSDP();
if (!rsdp) {
PrintKernelError("ACPI: RSDP not found\n");
return false;
}

PrintKernel("ACPI: Found RSDP at 0x");
PrintKernelHex((uint64_t)rsdp);
PrintKernel("\n");

// Validate RSDP checksum

if (!ValidateChecksum(rsdp, sizeof(ACPIRSDPv1))) {
PrintKernelError("ACPI: Invalid RSDP checksum\n");
return false;
}

ACPIRSDT* rsdt = (ACPIRSDT*)MapACPITable(rsdp->rsdt_address,
sizeof(ACPISDTHeader));
if (!rsdt) {
PrintKernelError("ACPI: Failed to map RSDT\n");
g_rsdt = (ACPIRSDT*)MapACPITable(rsdp->rsdt_address, sizeof(ACPISDTHeader));
if (!g_rsdt) {
PrintKernelError("ACPI: Failed to map RSDT header\n");
return false;
}
// Validate RSDT signature
if (FastMemcmp(rsdt->header.signature, ACPI_RSDT_SIG, 4) != 0) {

if (FastMemcmp(g_rsdt->header.signature, ACPI_RSDT_SIG, 4) != 0) {
PrintKernelError("ACPI: Invalid RSDT signature\n");
// Clean up the initial header‐only mapping
VMemUnmap((uint64_t)rsdt - (rsdp->rsdt_address & 0xFFF),
((sizeof(ACPISDTHeader) + (rsdp->rsdt_address & 0xFFF) + 0xFFF)
& ~0xFFF));
VMemUnmap((uint64_t)g_rsdt - (rsdp->rsdt_address & 0xFFF), ((sizeof(ACPISDTHeader) + (rsdp->rsdt_address & 0xFFF) + 0xFFF) & ~0xFFF));
return false;
}
// Remap with the full table length
uint32_t rsdt_size = rsdt->header.length;
// Remember the old header mapping so we can free it afterward
void* old_rsdt = rsdt;
uint32_t old_offset = rsdp->rsdt_address & 0xFFF;
rsdt = (ACPIRSDT*)MapACPITable(rsdp->rsdt_address, rsdt_size);
// Now unmap the temporary header‐only region
VMemUnmap((uint64_t)old_rsdt - old_offset,
((sizeof(ACPISDTHeader) + old_offset + 0xFFF) & ~0xFFF));

PrintKernel("ACPI: RSDT mapped, length=");
PrintKernelInt(rsdt_size);
PrintKernel("\n");

// Find FADT
uint32_t entries = (rsdt_size - sizeof(ACPISDTHeader)) / 4;
for (uint32_t i = 0; i < entries; i++) {
ACPISDTHeader* header = (ACPISDTHeader*)MapACPITable(
rsdt->table_pointers[i],
sizeof(ACPISDTHeader)
);
if (!header) continue;

bool is_fadt = FastMemcmp(header->signature, ACPI_FADT_SIG, 4) == 0;
uint32_t table_length = header->length;
uint32_t header_offset = rsdt->table_pointers[i] & 0xFFF;

// Unmap the header mapping now that we've inspected it
VMemUnmap(
(uint64_t)header - header_offset,
( (sizeof(ACPISDTHeader) + header_offset + 0xFFF) & ~0xFFF )
);

if (is_fadt) {
PrintKernel("ACPI: Found FADT\n");
g_fadt = (ACPIFADT*)MapACPITable(
rsdt->table_pointers[i],
table_length
);
break;
}

uint32_t rsdt_size = g_rsdt->header.length;
VMemUnmap((uint64_t)g_rsdt - (rsdp->rsdt_address & 0xFFF), ((sizeof(ACPISDTHeader) + (rsdp->rsdt_address & 0xFFF) + 0xFFF) & ~0xFFF));
g_rsdt = (ACPIRSDT*)MapACPITable(rsdp->rsdt_address, rsdt_size);
if (!g_rsdt) {
PrintKernelError("ACPI: Failed to map full RSDT\n");
return false;
}

PrintKernelError("ACPI: FADT not found or invalid\n");
return false;

g_fadt = (ACPIFADT*)AcpiFindTable(ACPI_FADT_SIG);
if (!g_fadt) {
PrintKernelError("ACPI: FADT not found or invalid\n");
return false;
}

g_acpi_initialized = true;
PrintKernelSuccess("ACPI: Subsystem initialized\n");
return true;
}

void ACPIResetProcedure() {
PrintKernel("ACPI: Unmounting Filesystems...\n");
VfsUnmountAll();
PrintKernelSuccess("ACPI: Filesystems unmounted\n");

PrintKernel("ACPI: Stopping all processes and services...\n");
KillAllProcess("SHUTDOWN");
PrintKernelSuccess("ACPI: All processes and services stopped\n");
}

void ACPIShutdown(void) {
if (!g_acpi_initialized || !g_fadt) {
PrintKernel("ACPI: Shutdown not available, using fallback\n");
outw(0x604, 0x2000);
return;
}

PrintKernel("ACPI: Initiating shutdown...\n");

// Enable ACPI mode if needed
if (g_fadt->smi_command_port && g_fadt->acpi_enable) {
PrintKernel("ACPI: Enabling ACPI mode via SMI\n");
outb(g_fadt->smi_command_port, g_fadt->acpi_enable);
}


ACPIResetProcedure();

// Try multiple shutdown methods
uint16_t shutdown_values[] = {0x2000, 0x3C00, 0x1400, 0x0000};

for (int i = 0; i < 4; i++) {
const uint16_t shutdown_values[] = {0x2000, 0x3C00, 0x1400, 0x0000};
PrintKernel("ACPI: Trying shutdown value 0x");
PrintKernelHex(shutdown_values[i]);
PrintKernel(" on port 0x");
Expand All @@ -180,18 +180,17 @@ void ACPIShutdown(void) {
// Wait a bit
delay(10);
}

// Fallback methods
PrintKernel("ACPI: Trying QEMU shutdown\n");
outw(0x604, 0x2000);


PrintKernel("ACPI: Trying Bochs shutdown\n");
outw(0xB004, 0x2000);

PrintKernelError("ACPI: All shutdown methods failed\n");
}

void ACPIReboot(void) {

ACPIResetProcedure();

PrintKernel("ACPI: Initiating reboot...\n");

// Try keyboard controller reset
Expand Down
3 changes: 2 additions & 1 deletion drivers/ACPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,5 @@ typedef struct {
// Function declarations
bool ACPIInit(void);
void ACPIShutdown(void);
void ACPIReboot(void);
void ACPIReboot(void);
void* AcpiFindTable(const char* signature);
30 changes: 28 additions & 2 deletions fs/EXT/Ext2.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ int Ext2ReadBlock(uint32_t block, void* buffer) {
return 0;
}

static FileSystemDriver ext2_driver = {"EXT2", Ext2Detect, Ext2Mount};
static FileSystemDriver ext2_driver = {"EXT2", Ext2Detect, Ext2Mount, Ext2Unmount};

int Ext2Mount(BlockDevice* device, const char* mount_point) {
// Prepare or reuse per-device volume
Expand Down Expand Up @@ -222,11 +222,37 @@ int Ext2Mount(BlockDevice* device, const char* mount_point) {
}
PrintKernelF("EXT2: Mounted filesystem\n");

PrintKernelSuccess("EXT2: Filesystem initialized successfully.\n");
PrintKernelSuccess("EXT2: Filesystem mounted.\n");
rust_rwlock_write_unlock(volume.lock);
return 0;
}

int Ext2Unmount(BlockDevice* device) {
if (!device) { return -1; }
int device_id = device->id;
if (device_id < 0 || device_id >= MAX_BLOCK_DEVICES) { return -1; }
Ext2Volume* vol = g_ext2_by_dev[device_id];
if (!vol) { return -1; } // Not mounted
RustRwLock* lock = vol->lock;
if (lock) {
rust_rwlock_write_lock(lock, GetCurrentProcess()->pid);
}
if (g_ext2_active == vol) {
g_ext2_active = NULL;
}
if (vol->group_descs) {
KernelFree(vol->group_descs);
vol->group_descs = NULL;
}
g_ext2_by_dev[device_id] = NULL;
if (lock) {
rust_rwlock_write_unlock(lock);
rust_rwlock_free(lock);
}
KernelFree(vol);
return 0;
}

int Ext2ReadInode(uint32_t inode_num, Ext2Inode* inode) {
rust_rwlock_read_lock(volume.lock, GetCurrentProcess()->pid);
if (inode_num == 0) {
Expand Down
1 change: 1 addition & 0 deletions fs/EXT/Ext2.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ typedef struct {

// Function prototypes for VFS integration
int Ext2Mount(BlockDevice* device, const char* mount_point);
int Ext2Unmount(BlockDevice* device);
int Ext2Detect(BlockDevice* device);
void Ext2SetActive(BlockDevice* device);
int Ext2ReadFile(const char* path, void* buffer, uint32_t max_size);
Expand Down
Loading