diff --git a/README.md b/README.md index 1199fb8..ebc12cb 100644 --- a/README.md +++ b/README.md @@ -1,141 +1,126 @@ -# VoidFrame Kernel Development Checklist +# [VoidFrame] - a syscall-less microkernel 💫 -> *This file tracks the current status of all core OS features for VoidFrame.* +> A fast, simple, secure 64-bit microkernel written in C and assembly. With modern capabilities. --- -## 🧱 Core Infrastructure - -- [x] Bootloader (GRUB2 with Multiboot2) -- [x] GDT & TSS setup -- [x] IDT & Interrupt Handling -- [x] PIC remapping & IRQ handling -- [x] PIT / Timer setup -- [x] Basic `printf` to VGA text mode -- [x] Kernel memory allocator -- [x] Panic screen with ASCII art (yes this is mandatory) - ---- - -## 🧠 Memory Management - -- [x] Physical memory manager (free list or bitmap) -- [x] Page table setup (paging enabled) -- [x] Virtual memory mapping API (`vmem_map()`, etc.) -- [x] Kernel heap (virtual, malloc/free) -- [ ] Per-process page tables -- [ ] User-mode memory protection - ---- - -## ⚙️ Process Management & Scheduling - -- [x] Process control block (PCB) -- [x] Scheduler (MLFQ) -- [x] Context switching -- [x] Preemption via PIT -- [x] Process creation -- [x] Process termination -- [x] Token/privilege-based validation -- [x] Scheduler aging/starvation fix -- [ ] CFS or vruntime-based scheduler (optional/bonus) - ---- - -## 🔐 Ring 3 Support (Userspace) (uhhh) - -- [ ] User-mode process flag -- [ ] IRETQ from syscall/interrupt -- [ ] Syscall handling (`syscall` or `int 0x80`) -- [ ] Userland stack setup -- [ ] Memory isolation (Ring 3 can't touch kernel) -- [ ] Transitioning back to kernel on syscall - ---- - -## 🧩 Module System - -- [x] Multiboot2 module loading -- [ ] Basic kernel extensions -- [ ] Signature/token validation -- [ ] Hot module unloading (optional) -- [ ] Module registration system - ---- - -## 📦 ELF Executable Support - -- [ ] ELF64 header parsing -- [ ] Program header mapping (`PT_LOAD`) -- [ ] Set up new stack -- [ ] Jump to entry point -- [ ] Static binaries only (no relocations) -- [ ] Dynamic linker / interpreter (WAY later) - ---- - -## 🧠 Init System - -- [ ] Create `init` process from `vmod` or ELF -- [x] Init spawns shell or TUI - ---- - -## 💬 IPC / Syscalls - -- [x] Syscall dispatch system -- [x] Basic message passing (pipe, queue, or buffer) -- [ ] Shared memory region -- [ ] Signals or async delivery -- [ ] Named channels or sockets +- Roadmap: [here!](docs/ROADMAP.md) +- How to build: [here!](docs/BUILD.md) --- -## 📁 Filesystem & I/O - -- [ ] Initrd loading -- [ ] Basic filesystem parsing (e.g., tarfs or ext2-lite) -- [x] Read/write file API (`fs_open()`, etc.) -- [x] VFS layer (optional) -- [ ] Device files (`/dev/null`, `/dev/tty0`, etc.) - ---- - -## 🧑‍💻 Userland Development - -- [ ] Userspace C runtime (libc-lite) -- [x] Shell (`sh.vmod` or `sh.elf`) -- [x] Basic CLI utilities (`cat`, `ls`, `echo`, etc.) -- [x] Keyboard driver -- [x] VGA console or terminal emulator - ---- - -## 🔧 Debug & Developer Features - -- [x] Print kernel logs to VGA -- [x] Serial logging -- [x] `dmesg`-style kernel log buffer -- [x] Stack backtrace / panic debug dump -- [x] Memory usage counters - ---- - -## 🌈 Extra Spice (optional but cool) - -- [x] Framebuffer graphics support -- [ ] Loadable GUI modules -- [ ] Virtual terminal switching (`tty0`, `tty1`) -- [ ] Profiling support (ticks per process) -- [ ] Syscall tracing / log -- [ ] Live module patching - ---- - -## 🏁 Final Goals (v1.0 release) - -- [ ] Bootable ISO with GRUB2 EFI support -- [ ] Fully self-hosted userland shell -- [ ] User process execution (ELF64) -- [ ] Init system + FS + IPC working -- [ ] At least one userland demo program +### Project Structure +``` +VoidFrame/ +├── arch/x86_64/ # Architechture specific code +│ ├── asm/ +│ │ └── pxs.asm +│ ├── cpu/ +│ │ ├── Cpu.h +│ │ └── Cpu.c +│ ├── gdt/ +│ │ ├── GdtTssFlush.asm +│ │ ├── Gdt.h +│ │ └── Gdt.c +│ ├── idt/ +│ │ ├── IdtLoad.asm +│ │ ├── Gdt.h +│ │ └── Gdt.c +│ └── interrupts/ +│ ├── Interrupts.asm +│ ├── Interrupts.c +│ └── Interrupts.h +├── drivers/ # Drivers code +│ ├── ethernet/ +│ │ ├── Packet.h +│ │ ├── RTL8139.h +│ │ └── RTL8139.c +│ ├── PCI/ +│ │ ├── PCI.h +│ │ └── PCI.c +│ ├── RTC/ +│ │ ├── Rtc.h +│ │ └── Rtc.c +│ ├── xHCI/ +│ │ ├── xHCI.h +│ │ └── xHCI.c +│ ├── Ide.h +│ ├── Ide.c +│ ├── Pic.h +│ ├── Pic.c +│ ├── PS2.h +│ ├── PS2.c +│ ├── Serial.c +│ ├── Serial.c +│ ├── VesaBIOSExtension.c +│ └── VesaBIOSExtension.h +├── fs/ +│ ├── FAT12.h # Filesystems +│ ├── FAT12.c +│ ├── Fs.h +│ ├── Fs.c +│ ├── FsUtils.h +│ ├── FsUtils.c +│ ├── VFS.c +│ └── VFS.h +├── include/ # Common includes +│ ├── Font.h +│ ├── Io.h +│ ├── Paging.h +│ ├── Paging.asm +│ ├── stdbool.h +│ ├── stdint.h +│ ├── stddef.h +│ ├── stdlib.h +│ └── stdarg.h +├── kernel/ # Kernel core +│ ├── atomic/ # Atomic operations +│ │ ├── Atomics.c +│ │ ├── Atomics.h +│ │ └── Spilock.h +│ ├── core/ # Entry point +│ │ ├── Kernel.h +│ │ ├── Kernel.c +│ │ ├── Panic.c +│ │ ├── Panic.c +│ │ └── Multiboot2.h +│ ├── elf/ # ELF loader +│ │ ├── ELFloader.c +│ │ └── ElFloader.h +│ ├── etc/ # Misc. files +│ │ ├── Console.c +│ │ ├── Console.h +│ │ ├── Editor.h +│ │ ├── Editor.c +│ │ ├── Shell.c +│ │ ├── Shell.h +│ │ ├── StringOps.c +│ │ ├── StringOps.h +│ │ ├── VBEConsole.c +│ │ └── VBEConsole.h +│ ├── ipc/ # IPC related files +│ │ ├── Ipc.c +│ │ └── Ipc.h +│ ├── memory/ # Physical and Virtual memory manager +│ │ ├── KernelHeap.c +│ │ ├── KernelHeap.h +│ │ ├── MemOps.h +│ │ ├── MemOps.c +│ │ ├── Memory.h +│ │ ├── Memory.c +│ │ ├── MemoryPool.c +│ │ ├── MemoryPool.h +│ │ ├── StackGuard.c +│ │ ├── StackGuard.h +│ │ ├── VMem.c +│ │ └── VMem.h +│ └── process/ # MLFQ scheduler +│ ├── Process.c +│ └── Process.h +├── scripts/ +│ └── elf.ld +├── linker.ld +├── grub.cfg +├── meson.build +└── ... +``` \ No newline at end of file diff --git a/docs/BUILD.md b/docs/BUILD.md new file mode 100644 index 0000000..bc4ac08 --- /dev/null +++ b/docs/BUILD.md @@ -0,0 +1,26 @@ +# Building the VoidFrame microkernel + +--- + +## Prerequisites + +- meson >= 1.0.0 +- ninja >= 1.11 +- clang >= 18.0.0 (or any C-compliant compiler) +- nasm >= 2.16 +- qemu >= 7.0.0 +- mkfs.fat (dosfstools) +- grub-mkrescue + - Note: depending on your distro, grub-mkrescue may require xorriso and mtools packages. + +### Quickstart +```bash +git clone https://github.com/assembler-0/VoidFrame.git +cd VoidFrame +meson setup build +cd build +ninja +ninja img && ninja mkfs # Optional +ninja run +``` + diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..86884d2 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,128 @@ +# VoidFrame Kernel Development Checklist + +> *This file tracks the current status of all core OS features for VoidFrame.* + +--- + +## 🧱 Core Infrastructure + +- [x] Bootloader (GRUB2 with Multiboot2) +- [x] GDT & TSS setup +- [x] IDT & Interrupt Handling +- [x] PIC remapping & IRQ handling +- [x] PIT / Timer setup +- [x] Basic `printf` to VGA text mode +- [x] Kernel memory allocator +- [x] Panic screen with ASCII art (yes this is mandatory) + +--- + +## 🧠 Memory Management + +- [x] Physical memory manager (free list or bitmap) +- [x] Page table setup (paging enabled) +- [x] Virtual memory mapping API (`vmem_map()`, etc.) +- [x] Kernel heap (virtual, malloc/free) + +--- + +## ⚙️ Process Management & Scheduling + +- [x] Process control block (PCB) +- [x] Scheduler (MLFQ) +- [x] Context switching +- [x] Preemption via PIT +- [x] Process creation +- [x] Process termination +- [x] Token/privilege-based validation +- [x] Scheduler aging/starvation fix +- [ ] CFS or vruntime-based scheduler (optional/bonus) + +--- + +## 🧩 Module System + +- [x] Multiboot2 module loading +- [ ] Basic kernel extensions +- [ ] Signature/token validation +- [ ] Hot module unloading (optional) +- [ ] Module registration system + +--- + +## 📦 ELF Executable Support + +- [x] ELF64 header parsing +- [x] Program header mapping (`PT_LOAD`) +- [x] Set up new stack +- [ ] Jump to entry point +- [x] Static binaries only (no relocations) +- [ ] Dynamic linker / interpreter (WAY later) + +--- + +## 🧠 Init System + +- [ ] Create `init` process from `vmod` or ELF +- [x] Init spawns shell or TUI + +--- + +## 💬 IPC / Syscalls + +- [x] Syscall dispatch system +- [x] Basic message passing (pipe, queue, or buffer) +- [ ] Shared memory region +- [ ] Signals or async delivery +- [ ] Named channels or sockets + +--- + +## 📁 Filesystem & I/O + +- [ ] Initrd loading +- [ ] Basic filesystem parsing (e.g., tarfs or ext2-lite) +- [x] Read/write file API (`fs_open()`, etc.) +- [x] VFS layer (optional) +- [ ] Device files (`/dev/null`, `/dev/tty0`, etc.) + +--- + +## 🧑‍💻 Userland Development + +- [ ] Userspace C runtime (libc-lite) +- [x] Shell (`sh.vmod` or `sh.elf`) +- [x] Basic CLI utilities (`cat`, `ls`, `echo`, etc.) +- [x] Keyboard driver +- [x] VGA console or terminal emulator + +--- + +## 🔧 Debug & Developer Features + +- [x] Print kernel logs to VGA +- [x] Serial logging +- [x] `dmesg`-style kernel log buffer +- [x] Stack backtrace / panic debug dump +- [x] Memory usage counters + +--- + +## 🌈 Extra Spice (optional but cool) + +- [x] Framebuffer graphics support +- [ ] Loadable GUI modules +- [ ] Virtual terminal switching (`tty0`, `tty1`) +- [ ] Profiling support (ticks per process) +- [ ] Syscall tracing / log +- [ ] Live module patching + +--- + +## 🏁 Final Goals (v1.0 release) + +- [ ] Bootable ISO with GRUB2 EFI support +- [ ] Fully self-hosted userland shell +- [ ] User process execution (ELF64) +- [ ] Init system + FS + IPC working +- [ ] At least one demo program diff --git a/fs/FAT12.c b/fs/FAT12.c index a7f6451..3cd3e59 100644 --- a/fs/FAT12.c +++ b/fs/FAT12.c @@ -4,6 +4,7 @@ #include "KernelHeap.h" #include "MemOps.h" #include "MemPool.h" +#include "Serial.h" #include "StringOps.h" static Fat12Volume volume; @@ -82,6 +83,7 @@ int Fat12Init(uint8_t drive) { return 0; } + // Get next cluster from FAT table static uint16_t Fat12GetNextCluster(uint16_t cluster) { if (cluster >= 0xFF8) return FAT12_CLUSTER_EOF; diff --git a/fs/FAT12.h b/fs/FAT12.h index 409e23e..f422f16 100644 --- a/fs/FAT12.h +++ b/fs/FAT12.h @@ -68,4 +68,4 @@ int Fat12CreateDir(const char* dirname); int Fat12ListRoot(void); int Fat12GetCluster(uint16_t cluster, uint8_t* buffer); int Fat12IsDirectory(const char* path); -int Fat12ListDirectory(const char* path); \ No newline at end of file +int Fat12ListDirectory(const char* path); diff --git a/fs/VFS.c b/fs/VFS.c index 33f98a2..815e591 100644 --- a/fs/VFS.c +++ b/fs/VFS.c @@ -264,6 +264,69 @@ int VfsDelete(const char* path) { return -1; } +uint64_t VfsGetFileSize(const char* path) { + if (!path) { + SerialWrite("[VFS] VfsGetFileSize: NULL path\n"); + return 0; + } + + if (FastStrlen(path, VFS_MAX_PATH_LEN) == 0) { + SerialWrite("[VFS] VfsGetFileSize: Empty path\n"); + return 0; + } + + VfsMountStruct* mount = VfsFindMount(path); + if (!mount) { + SerialWrite("[VFS] VfsGetFileSize: No mount found for path\n"); + return 0; + } + + const char* local_path = VfsStripMount(path, mount); + if (!local_path) { + SerialWrite("[VFS] VfsGetFileSize: Path strip failed\n"); + return 0; + } + + switch (mount->type) { + case VFS_RAMFS: { + // Normalize empty path to root + if (FastStrlen(local_path, 2) == 0) local_path = "/"; + + FsNode* node = FsFind(local_path); + if (!node) { + SerialWrite("[VFS] VfsGetFileSize: File not found in RAMFS\n"); + return 0; + } + + if (node->type != FS_FILE) { + SerialWrite("[VFS] VfsGetFileSize: Path is not a file in RAMFS\n"); + return 0; + } + + SerialWrite("[VFS] VfsGetFileSize: RAMFS file found, size: "); + SerialWriteDec((uint32_t)node->size); + SerialWrite("\n"); + return node->size; + } + + case VFS_FAT12: { + extern int fat12_initialized; + if (!fat12_initialized) return 0; + // assume + char test_buffer[1]; + int result = Fat12ReadFile(local_path, test_buffer, 1); + if (result < 0) return 0; // File doesn't exist + + return 1024 * 1024; + + } + + default: + SerialWrite("[VFS] VfsGetFileSize: Unknown filesystem type\n"); + return 0; + } +} + int VfsIsDir(const char* path) { VfsMountStruct* mount = VfsFindMount(path); if (!mount) return 0; diff --git a/fs/VFS.h b/fs/VFS.h index 46945d2..ec923d0 100644 --- a/fs/VFS.h +++ b/fs/VFS.h @@ -26,7 +26,7 @@ int VfsCreateFile(const char* path); int VfsCreateDir(const char* path); int VfsDelete(const char* path); int VfsIsDir(const char* path); - +uint64_t VfsGetFileSize(const char* path); // Internal VfsMountStruct* VfsFindMount(const char* path); const char* VfsStripMount(const char* path, VfsMountStruct* mount); \ No newline at end of file diff --git a/include/stdint.h b/include/stdint.h index f9ff484..3ec17d8 100644 --- a/include/stdint.h +++ b/include/stdint.h @@ -8,6 +8,12 @@ #define NULL ((void*)0) #define INT32_MAX ((int32_t)0x7FFFFFFF) #define INT32_MIN ((int32_t)0x80000000) +#define UINT32_MAX ((uint32_t)0xFFFFFFFF) +#define UINT32_MIN ((uint32_t)0x00000000) +#define INT64_MAX ((int64_t)0x7FFFFFFFFFFFFFFF) +#define INT64_MIN ((int64_t)0x8000000000000000) +#define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFF) +#define UINT64_MIN ((uint64_t)0x0000000000000000) typedef unsigned char uint8_t; _Static_assert(sizeof(uint8_t) == 1, "sizeof(uint8_t) != 1"); diff --git a/kernel/elf/ELFloader.c b/kernel/elf/ELFloader.c index 7825026..ff0950a 100644 --- a/kernel/elf/ELFloader.c +++ b/kernel/elf/ELFloader.c @@ -4,115 +4,229 @@ #include "MemOps.h" #include "Process.h" #include "VFS.h" +#include "VMem.h" +#include "Panic.h" +#include "StackGuard.h" -void* CreateProcessFromElf(const char* filename) { - // 1. Read ELF file from VFS - uint8_t* elf_data = (uint8_t*)KernelMemoryAlloc(65536); - if (!elf_data) { - PrintKernel("Failed to allocate memory for ELF data\n"); - return NULL; - } +// Default maximum ELF file size (4MB) +#define MAX_ELF_FILE_SIZE (4 * 1024 * 1024) - int bytes_read = VfsReadFile(filename, (char*)elf_data, 65536); +// Default process memory limit (16MB) +#define DEFAULT_PROCESS_MEMORY_LIMIT (16 * 1024 * 1024) - if (bytes_read <= 0) { - PrintKernel("Failed to read ELF file\n"); - KernelFree(elf_data); - return NULL; +static int ValidateElfHeader(const ElfHeader* header, uint64_t file_size) { + // Check magic bytes + if (header->e_ident[0] != 0x7F || + header->e_ident[1] != 'E' || + header->e_ident[2] != 'L' || + header->e_ident[3] != 'F') { + PrintKernelError("ELF: Invalid magic bytes\n"); + return 0; } - PrintKernel("1 - ELF file read successfully\n"); - // 2. Validate ELF header with proper bounds checking - if (sizeof(ElfHeader) > 65536) { - PrintKernel("ELF header too large"); - KernelFree(elf_data); - return NULL; + // Check class (64-bit) + if (header->e_ident[4] != ELFCLASS64) { + PrintKernelError("ELF: Only 64-bit ELF files supported\n"); + return 0; } - ElfHeader* header = (ElfHeader*)elf_data; + // Check data encoding (little-endian) + if (header->e_ident[5] != ELFDATA2LSB) { + PrintKernelError("ELF: Only little-endian ELF files supported\n"); + return 0; + } - // Check magic bytes properly (ELF magic is 0x7F454C46 in little endian) - if (header->e_ident[0] != 0x7F || - header->e_ident[1] != 'E' || - header->e_ident[2] != 'L' || - header->e_ident[3] != 'F') { - PrintKernel("Invalid ELF magic\n"); - KernelFree(elf_data); - return NULL; + // Check file type (executable) + if (header->e_type != ET_EXEC && header->e_type != ET_DYN) { + PrintKernelError("ELF: Only executable files supported\n"); + return 0; } // Check architecture if (header->e_machine != EM_X86_64) { - PrintKernel("Unsupported architecture\n"); - KernelFree(elf_data); - return NULL; + PrintKernelError("ELF: Only x86-64 architecture supported\n"); + return 0; + } + + // Validate program header table bounds + if (header->e_phoff + (header->e_phnum * header->e_phentsize) > file_size) { + PrintKernelError("ELF: Program header table out of bounds\n"); + return 0; } - // Check if program header table is within bounds - if (header->e_phoff + (header->e_phnum * header->e_phentsize) > 65536) { - PrintKernel("Program header table out of bounds\n"); - KernelFree(elf_data); - return NULL; + // Check for reasonable limits + if (header->e_phnum > 64) { + PrintKernelError("ELF: Too many program headers\n"); + return 0; } - PrintKernel("2 - ELF header validated\n"); + if (header->e_entry == 0) { + PrintKernelError("ELF: Invalid entry point\n"); + return 0; + } - // 3. Find PT_LOAD segments and allocate memory - ProgramHeader* ph = (ProgramHeader*)(elf_data + header->e_phoff); - void* process_memory = NULL; - uint64_t entry_point = header->e_entry; - uint64_t base_vaddr = 0; - uint64_t total_size = 0; + return 1; +} + +int ValidateElfFile(const uint8_t* elf_data, uint64_t size) { + if (!elf_data || size < sizeof(ElfHeader)) { + return 0; + } + + const ElfHeader* header = (const ElfHeader*)elf_data; + return ValidateElfHeader(header, size); +} + +static uint64_t CalculateProcessMemorySize(const ElfHeader* header, const uint8_t* elf_data) { + const ProgramHeader* ph = (const ProgramHeader*)(elf_data + header->e_phoff); + uint64_t lowest_addr = UINT64_MAX; + uint64_t highest_addr = 0; - // First pass: calculate total memory needed for (int i = 0; i < header->e_phnum; i++) { if (ph[i].p_type == PT_LOAD) { - if (base_vaddr == 0) { - base_vaddr = ph[i].p_vaddr; + if (ph[i].p_vaddr < lowest_addr) { + lowest_addr = ph[i].p_vaddr; } - uint64_t segment_end = ph[i].p_vaddr + ph[i].p_memsz - base_vaddr; - if (segment_end > total_size) { - total_size = segment_end; + uint64_t segment_end = ph[i].p_vaddr + ph[i].p_memsz; + if (segment_end > highest_addr) { + highest_addr = segment_end; } } } - if (total_size == 0) { - PrintKernel("No loadable segments found\n"); - KernelFree(elf_data); - return NULL; + if (lowest_addr == UINT64_MAX) { + return 0; // No loadable segments } - // Allocate contiguous memory for entire process image - process_memory = KernelMemoryAlloc(total_size); + return highest_addr - lowest_addr; +} + +uint32_t CreateProcessFromElf(const char* filename, const ElfLoadOptions* options) { + if (!filename) { + PrintKernelError("ELF: NULL filename provided\n"); + return 0; + } + + // Set default options if none provided + ElfLoadOptions default_opts = { + .privilege_level = PROC_PRIV_USER, + .security_flags = 0, + .max_memory = DEFAULT_PROCESS_MEMORY_LIMIT, + .process_name = filename + }; + + if (!options) { + options = &default_opts; + } + + // Security check: Only system processes can create system processes + Process* creator = GetCurrentProcess(); + if (options->privilege_level == PROC_PRIV_SYSTEM && + creator->privilege_level != PROC_PRIV_SYSTEM) { + PrintKernelError("ELF: Unauthorized attempt to create system process\n"); + return 0; + } + + PrintKernelSuccess("ELF: Loading executable: "); + PrintKernel(filename); + PrintKernel("\n"); + + // 1. Determine file size first + uint64_t file_size = VfsGetFileSize(filename); + if (file_size == 0 || file_size > MAX_ELF_FILE_SIZE) { + PrintKernelError("ELF: File too large or empty ("); + PrintKernelInt((uint32_t)file_size); + PrintKernel(" bytes)\n"); + return 0; + } + + // 2. Allocate memory for ELF file with guards + uint8_t* elf_data = (uint8_t*)VMemAllocWithGuards(file_size); + if (!elf_data) { + PrintKernelError("ELF: Failed to allocate memory for ELF data\n"); + return 0; + } + + // 3. Read ELF file from VFS + int bytes_read = VfsReadFile(filename, (char*)elf_data, file_size); + if (bytes_read <= 0 || (uint64_t)bytes_read != file_size) { + PrintKernelError("ELF: Failed to read file completely\n"); + VMemFreeWithGuards(elf_data, file_size); + return 0; + } + + PrintKernelSuccess("ELF: File loaded ("); + PrintKernelInt((uint32_t)bytes_read); + PrintKernel(" bytes)\n"); + + // 4. Validate ELF header + if (!ValidateElfFile(elf_data, file_size)) { + PrintKernelError("ELF: File validation failed\n"); + VMemFreeWithGuards(elf_data, file_size); + return 0; + } + + const ElfHeader* header = (const ElfHeader*)elf_data; + PrintKernelSuccess("ELF: Header validation passed\n"); + + // 5. Calculate required memory for process + uint64_t process_memory_size = CalculateProcessMemorySize(header, elf_data); + if (process_memory_size == 0) { + PrintKernelError("ELF: No loadable segments found\n"); + VMemFreeWithGuards(elf_data, file_size); + return 0; + } + + if (process_memory_size > options->max_memory) { + PrintKernelError("ELF: Process memory requirement ("); + PrintKernelInt((uint32_t)process_memory_size); + PrintKernel(") exceeds limit ("); + PrintKernelInt((uint32_t)options->max_memory); + PrintKernel(")\n"); + VMemFreeWithGuards(elf_data, file_size); + return 0; + } + + // 6. Allocate protected memory for process image + void* process_memory = VMemAllocWithGuards(process_memory_size); if (!process_memory) { - PrintKernel("Failed to allocate process memory\n"); - KernelFree(elf_data); - return NULL; + PrintKernelError("ELF: Failed to allocate process memory\n"); + VMemFreeWithGuards(elf_data, file_size); + return 0; } - // Initialize all memory to zero - FastMemset(process_memory, 0, total_size); + // Initialize memory to zero + FastMemset(process_memory, 0, process_memory_size); - // Second pass: load segments + // 7. Load segments into memory + const ProgramHeader* ph = (const ProgramHeader*)(elf_data + header->e_phoff); + uint64_t base_vaddr = UINT64_MAX; + + // Find the base virtual address + for (int i = 0; i < header->e_phnum; i++) { + if (ph[i].p_type == PT_LOAD && ph[i].p_vaddr < base_vaddr) { + base_vaddr = ph[i].p_vaddr; + } + } + + // Load each PT_LOAD segment for (int i = 0; i < header->e_phnum; i++) { if (ph[i].p_type == PT_LOAD) { // Validate segment bounds - if (ph[i].p_offset + ph[i].p_filesz > 65536) { - PrintKernel("Segment data out of ELF bounds\n"); - KernelFree(process_memory); - KernelFree(elf_data); - return NULL; + if (ph[i].p_offset + ph[i].p_filesz > file_size) { + PrintKernelError("ELF: Segment data out of file bounds\n"); + VMemFreeWithGuards(process_memory, process_memory_size); + VMemFreeWithGuards(elf_data, file_size); + return 0; } - // Calculate offset within allocated memory + // Calculate memory offset uint64_t mem_offset = ph[i].p_vaddr - base_vaddr; - - if (mem_offset + ph[i].p_memsz > total_size) { - PrintKernel("Segment exceeds allocated memory\n"); - KernelFree(process_memory); - KernelFree(elf_data); - return NULL; + if (mem_offset + ph[i].p_memsz > process_memory_size) { + PrintKernelError("ELF: Segment exceeds allocated memory\n"); + VMemFreeWithGuards(process_memory, process_memory_size); + VMemFreeWithGuards(elf_data, file_size); + return 0; } // Copy file data to memory @@ -122,32 +236,63 @@ void* CreateProcessFromElf(const char* filename) { ph[i].p_filesz); } - // BSS section is already zeroed from initial memset - PrintKernel("Loaded segment\n"); + // Zero out BSS if p_memsz > p_filesz + if (ph[i].p_memsz > ph[i].p_filesz) { + FastMemset((uint8_t*)process_memory + mem_offset + ph[i].p_filesz, + 0, + ph[i].p_memsz - ph[i].p_filesz); + } + + PrintKernelSuccess("ELF: Loaded segment "); + PrintKernelInt(i); + PrintKernel(" ("); + PrintKernelInt((uint32_t)ph[i].p_memsz); + PrintKernel(" bytes)\n"); } } - PrintKernel("3 - All segments loaded\n"); + // 8. Calculate adjusted entry point + uint64_t entry_point = header->e_entry; + if (entry_point < base_vaddr || entry_point >= base_vaddr + process_memory_size) { + PrintKernelError("ELF: Entry point outside loaded segments\n"); + VMemFreeWithGuards(process_memory, process_memory_size); + VMemFreeWithGuards(elf_data, file_size); + return 0; + } - // 4. Create kernel process - // Adjust entry point to be relative to our allocated memory void* adjusted_entry = (uint8_t*)process_memory + (entry_point - base_vaddr); - uint32_t pid = CreateProcess((void (*)(void))adjusted_entry); - KernelFree(elf_data); + // 9. Create process with enhanced security + uint32_t pid = CreateProcess( + (void (*)(void))adjusted_entry + ); + + // Clean up temporary ELF data + VMemFreeWithGuards(elf_data, file_size); if (pid == 0) { - PrintKernel("Failed to create process\n"); - KernelFree(process_memory); - return NULL; + PrintKernelError("ELF: Failed to create process\n"); + VMemFreeWithGuards(process_memory, process_memory_size); + return 0; } - PrintKernel("4 - Process created successfully\n"); - return (void*)(uintptr_t)pid; + PrintKernelSuccess("ELF: Process created successfully (PID: "); + PrintKernelInt(pid); + PrintKernel(")\n"); + + // Check for resource leaks after ELF loading + CheckResourceLeaks(); + + return pid; +} + +// Simple wrapper for backward compatibility +uint32_t LoadElfExecutable(const char* filename) { + return CreateProcessFromElf(filename, NULL); } -// Convenience function +// Legacy compatibility function int LoadElfFromFile(const char* filename) { - void* process = CreateProcessFromElf(filename); - return process ? 0 : -1; + uint32_t pid = LoadElfExecutable(filename); + return pid ? 0 : -1; } \ No newline at end of file diff --git a/kernel/elf/ELFloader.h b/kernel/elf/ELFloader.h index 38deac4..9fec8f5 100644 --- a/kernel/elf/ELFloader.h +++ b/kernel/elf/ELFloader.h @@ -16,6 +16,9 @@ typedef struct { uint16_t e_ehsize; // ELF header size uint16_t e_phentsize; // Program header table entry size uint16_t e_phnum; // Program header table entry count + uint16_t e_shentsize; // Section header table entry size + uint16_t e_shnum; // Section header table entry count + uint16_t e_shstrndx; // Section header string table index } ElfHeader; // Program Header @@ -30,12 +33,47 @@ typedef struct { uint64_t p_align; // Segment alignment } ProgramHeader; -#define ELF_MAGIC 0x464C457F // "\x7FELF" -#define PT_LOAD 1 -#define EM_X86_64 62 +// ELF File Classes +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// ELF Data Encoding +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// ELF File Types +#define ET_NONE 0 // No file type +#define ET_REL 1 // Relocatable file +#define ET_EXEC 2 // Executable file +#define ET_DYN 3 // Shared object file + +// Program Header Types +#define PT_NULL 0 // Unused entry +#define PT_LOAD 1 // Loadable segment +#define PT_DYNAMIC 2 // Dynamic linking info +#define PT_INTERP 3 // Interpreter path +#define PT_NOTE 4 // Auxiliary info + +// Program Header Flags +#define PF_X 1 // Execute +#define PF_W 2 // Write +#define PF_R 4 // Read + +#define ELF_MAGIC 0x464C457F // "\x7FELF" +#define EM_X86_64 62 + +// Enhanced API +typedef struct { + uint8_t privilege_level; // PROC_PRIV_USER or PROC_PRIV_SYSTEM + uint32_t security_flags; // Additional security flags + uint64_t max_memory; // Memory limit for process + const char* process_name; // Optional process name for debugging +} ElfLoadOptions; // Main functions int LoadElfFromFile(const char* filename); -void* CreateProcessFromElf(const char* filename); +uint32_t CreateProcessFromElf(const char* filename, const ElfLoadOptions* options); +uint32_t LoadElfExecutable(const char* filename); // Simple wrapper +int ValidateElfFile(const uint8_t* elf_data, uint64_t size); -#endif // VOIDFRAME_ELFLOADER_H +#endif // VOIDFRAME_ELFLOADER_H \ No newline at end of file diff --git a/kernel/etc/Shell.c b/kernel/etc/Shell.c index 1852a4a..be7525d 100644 --- a/kernel/etc/Shell.c +++ b/kernel/etc/Shell.c @@ -174,6 +174,7 @@ static void show_help() { PrintKernel(" perf - Show performance stats\n"); PrintKernel(" memstat - Show memory statistics\n"); PrintKernel(" setfreq - Set PIT timer \n"); + PrintKernel(" filesize - Get size of in bytes\n"); PrintKernel(" lspci - List current PCI device(s)\n"); PrintKernel(" lsusb - List current USB device(s) and xHCI controller(s)\n"); PrintKernel(" arptest - Perform an ARP test and send packets\n"); @@ -416,15 +417,38 @@ static void ExecuteCommand(const char* cmd) { } else { PrintKernel("Usage: mkdir \n"); } + } else if (FastStrCmp(cmd_name, "filesize") == 0) { + char* filename = GetArg(cmd, 1); + if (filename) { + uint64_t size = VfsGetFileSize(filename); + PrintKernel("File size: "); + PrintKernelInt((uint32_t)size); + PrintKernel(" bytes\n"); + KernelFree(filename); + } else { + PrintKernel("Usage: filesize \n"); + } } else if (FastStrCmp(cmd_name, "elfload") == 0) { char* name = GetArg(cmd, 1); if (name) { char full_path[256]; ResolvePath(name, full_path, 256); - if (LoadElfFromFile(full_path) == 0) { - PrintKernel("ELF Executable loaded\n"); + + // Enhanced options for ELF loading + ElfLoadOptions opts = { + .privilege_level = PROC_PRIV_USER, + .security_flags = 0, + .max_memory = 16 * 1024 * 1024, // 16MB limit + .process_name = full_path + }; + + uint32_t pid = CreateProcessFromElf(full_path, &opts); + if (pid != 0) { + PrintKernelSuccess("ELF Executable loaded (PID: "); + PrintKernelInt(pid); + PrintKernel(")\n"); } else { - PrintKernel("Failed to load ELF executable\n"); + PrintKernelError("Failed to load ELF executable\n"); } KernelFree(name); } else { diff --git a/kernel/memory/StackGuard.h b/kernel/memory/StackGuard.h index dc95794..5bfa960 100644 --- a/kernel/memory/StackGuard.h +++ b/kernel/memory/StackGuard.h @@ -2,6 +2,8 @@ #define STACK_GUARD_H #include "stdint.h" +#include "Memory.h" +#include "Console.h" #define STACK_CANARY_VALUE 0xDEADBEEFCAFEBABE @@ -10,4 +12,38 @@ extern uint64_t __stack_chk_guard; void __stack_chk_fail(void); void StackGuardInit(void); +static inline void CheckResourceLeaks(void) { + static uint64_t last_alloc_count = 0; + static uint64_t last_free_count = 0; + static uint64_t leak_check_counter = 0; + static int initialized = 0; + // Only sample every 100 calls to keep overhead low + if (++leak_check_counter % 100 != 0) { + return; + } + MemoryStats stats; + GetDetailedMemoryStats(&stats); + // Establish a baseline on first sample to avoid a guaranteed false positive + if (!initialized) { + last_alloc_count = stats.allocation_count; + last_free_count = stats.free_count; + initialized = 1; + return; + } + uint64_t delta_alloc = stats.allocation_count - last_alloc_count; + uint64_t delta_free = stats.free_count - last_free_count; + uint64_t net_growth = (delta_alloc > delta_free) + ? (delta_alloc - delta_free) + : 0; + // Heuristic: warn on notable net growth over the last window + if (net_growth > 64 && delta_alloc > (delta_free * 2)) { + PrintKernelWarning("Potential memory leak detected: "); + PrintKernel("net +"); + PrintKernelInt((uint32_t)net_growth); + PrintKernel(" allocations since last check\n"); + } + last_alloc_count = stats.allocation_count; + last_free_count = stats.free_count; +} + #endif \ No newline at end of file diff --git a/kernel/process/Process.c b/kernel/process/Process.c index fbba92d..bff4c40 100644 --- a/kernel/process/Process.c +++ b/kernel/process/Process.c @@ -10,6 +10,7 @@ #include "Serial.h" #include "Shell.h" #include "Spinlock.h" +#include "StackGuard.h" #include "VMem.h" #include "stdbool.h" #include "stdlib.h" @@ -1428,33 +1429,10 @@ void DynamoX(void) { last_context_switches = context_switches; } - // Shorter yield for better responsiveness - for (volatile int i = 0; i < 30000; i++); // Reduced from standard Yield() - } -} - -static int SecureTokenUpdate(Process* proc, uint8_t new_flags) { - if (!proc || proc->pid == 0) return 0; - - // Only allow self-modification or system process modification - Process* caller = GetCurrentProcess(); - if (caller->pid != proc->pid && caller->privilege_level != PROC_PRIV_SYSTEM) { - return 0; // Unauthorized + Yield(); } - - // Create new token with updated flags - SecurityToken new_token = proc->token; - new_token.flags |= new_flags; - new_token.checksum = 0; // Clear for recalculation - new_token.checksum = CalculateSecureChecksum(&new_token, proc->pid); - - // Atomic update - proc->token = new_token; - return 1; } - - void Astra(void) { PrintKernelSuccess("Astra: Astra initializing...\n"); Process* current = GetCurrentProcess(); @@ -1615,6 +1593,7 @@ void Astra(void) { } CleanupTerminatedProcesses(); + CheckResourceLeaks(); Yield(); } } diff --git a/scripts/converter.sh b/scripts/converter.sh deleted file mode 100644 index 1d1d634..0000000 --- a/scripts/converter.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# Use -depth 8 RGB: to force RGB format (3 bytes per pixel) without alpha -convert splash1.png -depth 8 -resize 800x600! RGB:splash1.raw -convert splash2.png -depth 8 -resize 800x600! RGB:splash2.raw -convert splash3.png -depth 8 -resize 800x600! RGB:splash3.raw -convert splash4.png -depth 8 -resize 800x600! RGB:splash4.raw - -# Then pack to 32-bit format for your framebuffer -for i in 1 2 3 4; do - python3 -c " -import struct -with open('splash${i}.raw', 'rb') as f: - data = f.read() -with open('splash${i}_32.raw', 'wb') as f: - for i in range(0, len(data), 3): - r, g, b = data[i], data[i+1], data[i+2] - # Pack as 0x00RRGGBB (32-bit) - f.write(struct.pack('