diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 46dc878..e4bbec1 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -2,10 +2,8 @@ name: VoidFrame kernel build on: - push: - branches: [ main, dev ] pull_request: - branches: [ main ] + branches: [ main, dev ] release: types: [created] diff --git a/README.md b/README.md index f2df4f1..2a97cba 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/drivers/virtio/VirtioBlk.c b/drivers/virtio/VirtioBlk.c index 3dece30..771c46c 100644 --- a/drivers/virtio/VirtioBlk.c +++ b/drivers/virtio/VirtioBlk.c @@ -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; @@ -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) { @@ -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) -} \ No newline at end of file + + 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; +} diff --git a/drivers/virtio/VirtioBlk.h b/drivers/virtio/VirtioBlk.h index 2800240..72ec1e5 100644 --- a/drivers/virtio/VirtioBlk.h +++ b/drivers/virtio/VirtioBlk.h @@ -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 diff --git a/scripts/mangle.py b/scripts/mangle.py new file mode 100644 index 0000000..b9ddfee --- /dev/null +++ b/scripts/mangle.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +""" +C Function Name Mangler +Obfuscates function names in C source code to make reverse engineering annoying +""" + +import os +import re +import random +import string +import json +from pathlib import Path + +class CNameMangler: + def __init__(self): + self.mapping = {} + self.reserved_words = { + # C keywords + 'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', + 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', + 'int', 'long', 'register', 'return', 'short', 'signed', 'sizeof', 'static', + 'struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while', + # Common libc functions you might not want to mangle + 'printf', 'malloc', 'free', 'memcpy', 'strlen', 'strcmp', + # Your kernel entry points you might want to keep + 'kmain', '_start', 'kernel_main' + } + self.protected_functions = set() + + def generate_mangled_name(self, original_name): + """Generate a mangled name that looks like compiler output""" + if original_name in self.mapping: + return self.mapping[original_name] + + # Different mangling styles + styles = [ + self._generate_hex_style, + self._generate_underscore_style, + self._generate_mixed_style, + self._generate_compiler_style + ] + + style = random.choice(styles) + mangled = style(original_name) + + # Ensure uniqueness + while mangled in self.mapping.values() or mangled in self.reserved_words: + mangled = style(original_name) + + self.mapping[original_name] = mangled + return mangled + + def _generate_hex_style(self, name): + """Generate names like _func_a2b3c4d5""" + hex_suffix = ''.join(random.choices('0123456789abcdef', k=8)) + return f"_func_{hex_suffix}" + + def _generate_underscore_style(self, name): + """Generate names like __ZN4kern5mmgr7E""" + random_chars = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8)) + return f"__ZN{len(name)}{random_chars}E" + + def _generate_mixed_style(self, name): + """Generate names like _k7m3_fn_a4b2""" + prefix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4)) + suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=4)) + return f"_k{prefix}_fn_{suffix}" + + def _generate_compiler_style(self, name): + """Generate names that look like compiler internals""" + templates = [ + f"__builtin_{random.randint(1000, 9999)}", + f"_internal_func_{random.randint(100, 999)}", + f"__kern_impl_{random.randint(10, 99)}", + f"_sys_call_impl_{random.randint(1, 256)}" + ] + return random.choice(templates) + + def extract_functions(self, source_code): + """Extract function definitions and declarations""" + # Pattern for function definitions/declarations + # This is simplified - real C parsing is complex + patterns = [ + # Function definitions: return_type function_name(params) { + r'\b([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*\{', + # Function declarations: return_type function_name(params); + r'\b([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*;', + # Static functions + r'\bstatic\s+[a-zA-Z_][a-zA-Z0-9_]*\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)', + ] + + functions = set() + for pattern in patterns: + matches = re.finditer(pattern, source_code, re.MULTILINE) + for match in matches: + if len(match.groups()) >= 2: + func_name = match.group(2) + else: + func_name = match.group(1) + + # Skip reserved words and protected functions + if func_name not in self.reserved_words and func_name not in self.protected_functions: + functions.add(func_name) + + return functions + + def mangle_source_file(self, filepath): + """Mangle function names in a single source file""" + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + # Extract functions + functions = self.extract_functions(content) + + # Generate mappings for new functions + for func in functions: + if func not in self.mapping: + self.generate_mangled_name(func) + + # Replace function names + for original, mangled in self.mapping.items(): + # Replace function definitions and calls + patterns = [ + # Function definition: func_name( + (rf'\b{re.escape(original)}\s*\(', f'{mangled}('), + # Function calls: func_name( + (rf'\b{re.escape(original)}\b(?=\s*\()', mangled), + # Function pointers: &func_name + (rf'&\s*{re.escape(original)}\b', f'&{mangled}'), + ] + + for pattern, replacement in patterns: + content = re.sub(pattern, replacement, content) + + return content + + def mangle_project(self, source_dir, output_dir=None, file_extensions=None): + """Mangle an entire C project""" + if file_extensions is None: + file_extensions = ['.c', '.h'] + + if output_dir is None: + output_dir = source_dir + '_mangled' + + Path(output_dir).mkdir(exist_ok=True) + + # Process all C files + for root, dirs, files in os.walk(source_dir): + for file in files: + if any(file.endswith(ext) for ext in file_extensions): + source_path = os.path.join(root, file) + + # Calculate output path + rel_path = os.path.relpath(source_path, source_dir) + output_path = os.path.join(output_dir, rel_path) + + # Create output directory + os.makedirs(os.path.dirname(output_path), exist_ok=True) + + # Mangle the file + mangled_content = self.mangle_source_file(source_path) + + with open(output_path, 'w', encoding='utf-8') as f: + f.write(mangled_content) + + print(f"Mangled: {source_path} -> {output_path}") + + # Save mapping for debugging + mapping_file = os.path.join(output_dir, '_mangling_map.json') + with open(mapping_file, 'w') as f: + json.dump(self.mapping, f, indent=2) + + print(f"Mapping saved to: {mapping_file}") + print(f"Total functions mangled: {len(self.mapping)}") + +def main(): + import argparse + + parser = argparse.ArgumentParser(description='Mangle C function names') + parser.add_argument('source_dir', help='Source directory to mangle') + parser.add_argument('-o', '--output', help='Output directory') + parser.add_argument('--protect', nargs='*', help='Functions to protect from mangling') + parser.add_argument('--extensions', nargs='*', default=['.c', '.h'], + help='File extensions to process') + + args = parser.parse_args() + + mangler = CNameMangler() + + # Add protected functions + if args.protect: + mangler.protected_functions.update(args.protect) + + # Add kernel-specific protected functions + kernel_protected = { + 'kmain', '_start', 'kernel_main', 'interrupt_handler', + 'page_fault_handler', 'timer_interrupt', 'keyboard_interrupt' + } + mangler.protected_functions.update(kernel_protected) + + mangler.mangle_project(args.source_dir, args.output, args.extensions) + +if __name__ == '__main__': + main() diff --git a/vfconfig.py b/scripts/vfconfig.py similarity index 100% rename from vfconfig.py rename to scripts/vfconfig.py