From 7bf2b3a05939122f8cdd19424e32b86e2e1f401e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 21:43:30 +0000 Subject: [PATCH] Convert MetalOS from C to C++ with class-based design Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com> --- kernel/CMakeLists.txt | 14 +- kernel/include/kernel/apic.h | 28 +++- kernel/include/kernel/gdt.h | 24 +++- kernel/include/kernel/interrupts.h | 28 +++- kernel/include/kernel/kernel.h | 8 ++ kernel/include/kernel/memory.h | 45 +++++- kernel/include/kernel/pci.h | 45 +++++- kernel/include/kernel/smp.h | 42 ++++-- kernel/include/kernel/spinlock.h | 35 +++-- kernel/include/kernel/timer.h | 26 +++- kernel/src/{apic.c => apic.cpp} | 77 ++++++---- kernel/src/gdt.c | 56 -------- kernel/src/gdt.cpp | 64 +++++++++ kernel/src/{interrupts.c => interrupts.cpp} | 1 + kernel/src/{main.c => main.cpp} | 1 + kernel/src/{memory.c => memory.cpp} | 149 ++++++++++++-------- kernel/src/{pci.c => pci.cpp} | 113 ++++++++------- kernel/src/{smp.c => smp.cpp} | 1 + kernel/src/{spinlock.c => spinlock.cpp} | 71 ++++++++-- kernel/src/{timer.c => timer.cpp} | 52 +++++-- 20 files changed, 626 insertions(+), 254 deletions(-) rename kernel/src/{apic.c => apic.cpp} (50%) delete mode 100644 kernel/src/gdt.c create mode 100644 kernel/src/gdt.cpp rename kernel/src/{interrupts.c => interrupts.cpp} (99%) rename kernel/src/{main.c => main.cpp} (99%) rename kernel/src/{memory.c => memory.cpp} (50%) rename kernel/src/{pci.c => pci.cpp} (52%) rename kernel/src/{smp.c => smp.cpp} (99%) rename kernel/src/{spinlock.c => spinlock.cpp} (58%) rename kernel/src/{timer.c => timer.cpp} (68%) diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 72e139d..cef35e1 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -3,16 +3,16 @@ cmake_minimum_required(VERSION 3.16) -project(MetalOS_Kernel C ASM) +project(MetalOS_Kernel CXX ASM) # Source files # Note: Using GLOB for simplicity. For production, consider listing files explicitly. # If new files aren't detected, re-run cmake configuration. -file(GLOB KERNEL_C_SOURCES "src/*.c") +file(GLOB KERNEL_CXX_SOURCES "src/*.cpp") file(GLOB KERNEL_ASM_SOURCES "src/*.asm") set(KERNEL_SOURCES - ${KERNEL_C_SOURCES} + ${KERNEL_CXX_SOURCES} ) # Find NASM assembler @@ -42,7 +42,7 @@ else() endif() # Compiler flags for kernel -set(KERNEL_CFLAGS +set(KERNEL_CXXFLAGS -Wall -Wextra -Werror @@ -50,19 +50,21 @@ set(KERNEL_CFLAGS -fno-stack-protector -mno-red-zone -mcmodel=large + -fno-exceptions + -fno-rtti -O2 ) # Create object library add_library(kernel_obj OBJECT ${KERNEL_SOURCES}) target_include_directories(kernel_obj PRIVATE include) -target_compile_options(kernel_obj PRIVATE ${KERNEL_CFLAGS}) +target_compile_options(kernel_obj PRIVATE ${KERNEL_CXXFLAGS}) # Create kernel binary add_executable(kernel_elf $ ${KERNEL_ASM_OBJECTS}) set_target_properties(kernel_elf PROPERTIES OUTPUT_NAME metalos.elf - LINKER_LANGUAGE C + LINKER_LANGUAGE CXX POSITION_INDEPENDENT_CODE OFF ) target_link_options(kernel_elf PRIVATE diff --git a/kernel/include/kernel/apic.h b/kernel/include/kernel/apic.h index ed1c5c3..dab4832 100644 --- a/kernel/include/kernel/apic.h +++ b/kernel/include/kernel/apic.h @@ -19,11 +19,37 @@ #define APIC_IPI_INIT 0x500 #define APIC_IPI_STARTUP 0x600 -// APIC functions +#ifdef __cplusplus +// C++ APIC class +class APIC { +private: + volatile uint32_t* apicBase; + + uint32_t read(uint32_t offset) const; + void write(uint32_t offset, uint32_t value); + +public: + APIC(); + + bool isAvailable() const; + void init(); + uint8_t getId() const; + void sendEOI(); + void sendIPI(uint8_t destApicId, uint8_t vector, uint32_t deliveryMode); +}; + +extern "C" { +#endif + +// C-compatible APIC functions bool apic_is_available(void); void apic_init(void); uint8_t apic_get_id(void); void apic_send_eoi(void); void apic_send_ipi(uint8_t dest_apic_id, uint8_t vector, uint32_t delivery_mode); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_APIC_H diff --git a/kernel/include/kernel/gdt.h b/kernel/include/kernel/gdt.h index b170611..5d29d04 100644 --- a/kernel/include/kernel/gdt.h +++ b/kernel/include/kernel/gdt.h @@ -19,7 +19,29 @@ typedef struct { uint64_t base; } __attribute__((packed)) gdt_ptr_t; -// Initialize the Global Descriptor Table +#ifdef __cplusplus +// C++ GDT class +class GDT { +private: + gdt_entry_t entries[5]; + gdt_ptr_t gdtPtr; + + void setGate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran); + +public: + GDT(); + + void init(); +}; + +extern "C" { +#endif + +// C-compatible GDT function void gdt_init(void); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_GDT_H diff --git a/kernel/include/kernel/interrupts.h b/kernel/include/kernel/interrupts.h index d29dcd6..f353b3e 100644 --- a/kernel/include/kernel/interrupts.h +++ b/kernel/include/kernel/interrupts.h @@ -28,10 +28,32 @@ typedef struct { uint64_t rip, cs, rflags, rsp, ss; } __attribute__((packed)) registers_t; -// Initialize Interrupt Descriptor Table -void idt_init(void); +#ifdef __cplusplus +// C++ InterruptManager class +class InterruptManager { +private: + idt_entry_t idt[256]; + idt_ptr_t idtPtr; + + void setGate(uint8_t num, uint64_t handler, uint16_t selector, uint8_t flags); + void remapPIC(); -// Generic interrupt handler (called from assembly) +public: + InterruptManager(); + + void init(); + void handleInterrupt(registers_t* regs); +}; + +extern "C" { +#endif + +// C-compatible functions +void idt_init(void); void interrupt_handler(registers_t* regs); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_INTERRUPTS_H diff --git a/kernel/include/kernel/kernel.h b/kernel/include/kernel/kernel.h index 0955dce..b598920 100644 --- a/kernel/include/kernel/kernel.h +++ b/kernel/include/kernel/kernel.h @@ -27,7 +27,15 @@ typedef struct { void* rsdp; } BootInfo; +#ifdef __cplusplus +extern "C" { +#endif + // Kernel entry point void kernel_main(BootInfo* boot_info); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_KERNEL_H diff --git a/kernel/include/kernel/memory.h b/kernel/include/kernel/memory.h index ff0e4a9..c34b7f4 100644 --- a/kernel/include/kernel/memory.h +++ b/kernel/include/kernel/memory.h @@ -8,14 +8,51 @@ // Memory constants #define PAGE_SIZE 4096 -// Physical memory manager +#ifdef __cplusplus +// C++ PhysicalMemoryManager class +class PhysicalMemoryManager { +private: + uint8_t pageBitmap[32768]; // Supports up to 128MB with 4KB pages + uint64_t totalPages; + uint64_t usedPages; + +public: + PhysicalMemoryManager(); + + void init(BootInfo* bootInfo); + void* allocPage(); + void freePage(void* page); + uint64_t getTotalMemory() const; + uint64_t getFreeMemory() const; +}; + +// C++ HeapAllocator class +class HeapAllocator { +private: + uint8_t* heapStart; + uint8_t* heapCurrent; + uint8_t* heapEnd; + +public: + HeapAllocator(); + + void init(void* start, size_t size); + void* alloc(size_t size); + void* calloc(size_t num, size_t size); + void free(void* ptr); +}; + +extern "C" { +#endif + +// C-compatible physical memory manager void pmm_init(BootInfo* boot_info); void* pmm_alloc_page(void); void pmm_free_page(void* page); uint64_t pmm_get_total_memory(void); uint64_t pmm_get_free_memory(void); -// Simple kernel heap allocator (bump allocator for now) +// C-compatible kernel heap allocator void heap_init(void* start, size_t size); void* kmalloc(size_t size); void* kcalloc(size_t num, size_t size); @@ -26,4 +63,8 @@ void* memset(void* dest, int val, size_t count); void* memcpy(void* dest, const void* src, size_t count); int memcmp(const void* s1, const void* s2, size_t count); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_MEMORY_H diff --git a/kernel/include/kernel/pci.h b/kernel/include/kernel/pci.h index b3b0449..5cc160d 100644 --- a/kernel/include/kernel/pci.h +++ b/kernel/include/kernel/pci.h @@ -7,6 +7,9 @@ #define PCI_CONFIG_ADDRESS 0xCF8 #define PCI_CONFIG_DATA 0xCFC +// Maximum devices we'll track +#define MAX_PCI_DEVICES 256 + // PCI Device Structure typedef struct { uint8_t bus; @@ -21,11 +24,51 @@ typedef struct { uint32_t bar[6]; // Base Address Registers } pci_device_t; -// PCI Functions +#ifdef __cplusplus +// C++ PCIDevice class-compatible structure +struct PCIDevice { + uint8_t bus; + uint8_t device; + uint8_t function; + uint16_t vendor_id; + uint16_t device_id; + uint8_t class_code; + uint8_t subclass; + uint8_t prog_if; + uint8_t revision_id; + uint32_t bar[6]; +}; + +// C++ PCIManager class +class PCIManager { +private: + PCIDevice devices[MAX_PCI_DEVICES]; + uint32_t deviceCount; + + void probeDevice(uint8_t bus, uint8_t device, uint8_t function); + +public: + PCIManager(); + + void init(); + uint32_t readConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset); + void writeConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value); + PCIDevice* findDevice(uint16_t vendor_id, uint16_t device_id); + void enableBusMastering(PCIDevice* dev); +}; + +extern "C" { +#endif + +// C-compatible PCI functions void pci_init(void); uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset); void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value); pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id); void pci_enable_bus_mastering(pci_device_t* dev); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_PCI_H diff --git a/kernel/include/kernel/smp.h b/kernel/include/kernel/smp.h index e1a8113..03d8b1b 100644 --- a/kernel/include/kernel/smp.h +++ b/kernel/include/kernel/smp.h @@ -15,22 +15,42 @@ typedef struct { uint64_t kernel_stack; } cpu_info_t; -// SMP initialization +#ifdef __cplusplus +// C++ SMPManager class +class SMPManager { +private: + cpu_info_t cpuInfo[MAX_CPUS]; + uint8_t cpuCount; + bool smpEnabled; + + void initCPU(uint8_t cpuId, uint8_t apicId); + void delay(uint32_t microseconds); + bool startAP(uint8_t apicId); + +public: + SMPManager(); + + void init(); + uint8_t getCPUCount() const; + uint8_t getCurrentCPU() const; + bool isEnabled() const; + cpu_info_t* getCPUInfo(uint8_t cpuId); + void markCPUOnline(uint8_t cpuId); +}; + +extern "C" { +#endif + +// C-compatible SMP functions void smp_init(void); - -// Get number of CPUs detected uint8_t smp_get_cpu_count(void); - -// Get current CPU ID uint8_t smp_get_current_cpu(void); - -// Check if SMP is enabled bool smp_is_enabled(void); - -// Get CPU info cpu_info_t* smp_get_cpu_info(uint8_t cpu_id); - -// Mark CPU as online (internal use by AP startup) void smp_cpu_online(uint8_t cpu_id); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_SMP_H diff --git a/kernel/include/kernel/spinlock.h b/kernel/include/kernel/spinlock.h index 7ec431d..dd9a3ca 100644 --- a/kernel/include/kernel/spinlock.h +++ b/kernel/include/kernel/spinlock.h @@ -4,24 +4,39 @@ #include #include -// Spinlock structure +#ifdef __cplusplus +// C++ Spinlock class +class Spinlock { +private: + volatile uint32_t lock; + +public: + Spinlock(); + + void init(); + void acquire(); + bool tryAcquire(); + void release(); + bool isLocked() const; +}; + +extern "C" { +#endif + +// C-compatible spinlock structure typedef struct { volatile uint32_t lock; } spinlock_t; -// Initialize spinlock +// C-compatible functions void spinlock_init(spinlock_t* lock); - -// Acquire spinlock void spinlock_acquire(spinlock_t* lock); - -// Try to acquire spinlock (non-blocking) bool spinlock_try_acquire(spinlock_t* lock); - -// Release spinlock void spinlock_release(spinlock_t* lock); - -// Check if locked bool spinlock_is_locked(spinlock_t* lock); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_SPINLOCK_H diff --git a/kernel/include/kernel/timer.h b/kernel/include/kernel/timer.h index 3d93428..2dc83c4 100644 --- a/kernel/include/kernel/timer.h +++ b/kernel/include/kernel/timer.h @@ -6,12 +6,32 @@ // Timer frequency (Hz) #define TIMER_FREQUENCY 1000 // 1ms per tick -// Timer functions +#ifdef __cplusplus +// C++ Timer class +class Timer { +private: + volatile uint64_t ticks; + +public: + Timer(); + + void init(uint32_t frequency); + uint64_t getTicks() const; + void wait(uint32_t waitTicks) const; + void handleInterrupt(); +}; + +extern "C" { +#endif + +// C-compatible timer functions void timer_init(uint32_t frequency); uint64_t timer_get_ticks(void); void timer_wait(uint32_t ticks); - -// Timer interrupt handler (called from ISR) void timer_handler(void); +#ifdef __cplusplus +} +#endif + #endif // METALOS_KERNEL_TIMER_H diff --git a/kernel/src/apic.c b/kernel/src/apic.cpp similarity index 50% rename from kernel/src/apic.c rename to kernel/src/apic.cpp index e96f4c1..10bac9e 100644 --- a/kernel/src/apic.c +++ b/kernel/src/apic.cpp @@ -9,10 +9,9 @@ // APIC base address (default, can be read from MSR) #define APIC_BASE_MSR 0x1B -static volatile uint32_t* apic_base = (volatile uint32_t*)0xFEE00000; // Read CPUID to check for APIC -static bool cpuid_has_apic(void) { +static bool cpuidHasAPIC(void) { uint32_t eax, ebx, ecx, edx; // CPUID function 1 @@ -26,52 +25,76 @@ static bool cpuid_has_apic(void) { return (edx & (1 << 9)) != 0; } -// Read APIC register -static uint32_t apic_read(uint32_t offset) { - return apic_base[offset / 4]; +// APIC class implementation +APIC::APIC() : apicBase((volatile uint32_t*)0xFEE00000) {} + +uint32_t APIC::read(uint32_t offset) const { + return apicBase[offset / 4]; } -// Write APIC register -static void apic_write(uint32_t offset, uint32_t value) { - apic_base[offset / 4] = value; +void APIC::write(uint32_t offset, uint32_t value) { + apicBase[offset / 4] = value; } -// Check if APIC is available -bool apic_is_available(void) { - return cpuid_has_apic(); +bool APIC::isAvailable() const { + return cpuidHasAPIC(); } -// Initialize Local APIC -void apic_init(void) { +void APIC::init() { // Enable APIC via spurious interrupt vector register // Set spurious vector to 0xFF and enable APIC (bit 8) - apic_write(APIC_REG_SPURIOUS, 0x1FF); + write(APIC_REG_SPURIOUS, 0x1FF); // Set Task Priority Register to 0 (accept all interrupts) - apic_write(APIC_REG_TPR, 0); + write(APIC_REG_TPR, 0); } -// Get APIC ID -uint8_t apic_get_id(void) { - uint32_t id_reg = apic_read(APIC_REG_ID); - return (id_reg >> 24) & 0xFF; +uint8_t APIC::getId() const { + uint32_t idReg = read(APIC_REG_ID); + return (idReg >> 24) & 0xFF; } -// Send End of Interrupt -void apic_send_eoi(void) { - apic_write(APIC_REG_EOI, 0); +void APIC::sendEOI() { + write(APIC_REG_EOI, 0); } -// Send Inter-Processor Interrupt (IPI) -void apic_send_ipi(uint8_t dest_apic_id, uint8_t vector, uint32_t delivery_mode) { +void APIC::sendIPI(uint8_t destApicId, uint8_t vector, uint32_t deliveryMode) { // Wait for previous IPI to complete - while (apic_read(APIC_REG_ICR_LOW) & (1 << 12)) { + while (read(APIC_REG_ICR_LOW) & (1 << 12)) { __asm__ volatile("pause"); } // Set destination in high register - apic_write(APIC_REG_ICR_HIGH, ((uint32_t)dest_apic_id) << 24); + write(APIC_REG_ICR_HIGH, ((uint32_t)destApicId) << 24); // Send IPI with delivery mode and vector in low register - apic_write(APIC_REG_ICR_LOW, delivery_mode | vector); + write(APIC_REG_ICR_LOW, deliveryMode | vector); } + +// Global APIC instance +static APIC globalAPIC; + +// C-compatible wrapper functions +extern "C" { + +bool apic_is_available(void) { + return globalAPIC.isAvailable(); +} + +void apic_init(void) { + globalAPIC.init(); +} + +uint8_t apic_get_id(void) { + return globalAPIC.getId(); +} + +void apic_send_eoi(void) { + globalAPIC.sendEOI(); +} + +void apic_send_ipi(uint8_t dest_apic_id, uint8_t vector, uint32_t delivery_mode) { + globalAPIC.sendIPI(dest_apic_id, vector, delivery_mode); +} + +} // extern "C" diff --git a/kernel/src/gdt.c b/kernel/src/gdt.c deleted file mode 100644 index e5729d9..0000000 --- a/kernel/src/gdt.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * MetalOS Kernel - Global Descriptor Table (GDT) - * - * Minimal GDT setup for x86_64 long mode - * Only what's needed for our single-app OS - */ - -#include "kernel/gdt.h" - -// GDT entries (minimal for x86_64) -// In long mode, most segmentation is ignored, but we still need a valid GDT -static gdt_entry_t gdt[5]; -static gdt_ptr_t gdt_ptr; - -// Set a GDT entry -static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { - gdt[num].base_low = (base & 0xFFFF); - gdt[num].base_middle = (base >> 16) & 0xFF; - gdt[num].base_high = (base >> 24) & 0xFF; - - gdt[num].limit_low = (limit & 0xFFFF); - gdt[num].granularity = (limit >> 16) & 0x0F; - gdt[num].granularity |= gran & 0xF0; - gdt[num].access = access; -} - -// Load GDT (assembly) -extern void gdt_flush(uint64_t); - -// Initialize GDT -void gdt_init(void) { - gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; - gdt_ptr.base = (uint64_t)&gdt; - - // Null descriptor - gdt_set_gate(0, 0, 0, 0, 0); - - // Kernel code segment (64-bit) - // Access: Present, Ring 0, Code, Executable, Readable - gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xA0); - - // Kernel data segment (64-bit) - // Access: Present, Ring 0, Data, Writable - gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xC0); - - // User code segment (64-bit) - // Access: Present, Ring 3, Code, Executable, Readable - gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xA0); - - // User data segment (64-bit) - // Access: Present, Ring 3, Data, Writable - gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xC0); - - // Flush GDT - gdt_flush((uint64_t)&gdt_ptr); -} diff --git a/kernel/src/gdt.cpp b/kernel/src/gdt.cpp new file mode 100644 index 0000000..6100ca9 --- /dev/null +++ b/kernel/src/gdt.cpp @@ -0,0 +1,64 @@ +/* + * MetalOS Kernel - Global Descriptor Table (GDT) + * + * Minimal GDT setup for x86_64 long mode + * Only what's needed for our single-app OS + */ + +#include "kernel/gdt.h" + +// Load GDT (assembly) +extern "C" void gdt_flush(uint64_t); + +// GDT class implementation +GDT::GDT() { + gdtPtr.limit = (sizeof(gdt_entry_t) * 5) - 1; + gdtPtr.base = (uint64_t)&entries; +} + +void GDT::setGate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + entries[num].base_low = (base & 0xFFFF); + entries[num].base_middle = (base >> 16) & 0xFF; + entries[num].base_high = (base >> 24) & 0xFF; + + entries[num].limit_low = (limit & 0xFFFF); + entries[num].granularity = (limit >> 16) & 0x0F; + entries[num].granularity |= gran & 0xF0; + entries[num].access = access; +} + +void GDT::init() { + // Null descriptor + setGate(0, 0, 0, 0, 0); + + // Kernel code segment (64-bit) + // Access: Present, Ring 0, Code, Executable, Readable + setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xA0); + + // Kernel data segment (64-bit) + // Access: Present, Ring 0, Data, Writable + setGate(2, 0, 0xFFFFFFFF, 0x92, 0xC0); + + // User code segment (64-bit) + // Access: Present, Ring 3, Code, Executable, Readable + setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xA0); + + // User data segment (64-bit) + // Access: Present, Ring 3, Data, Writable + setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xC0); + + // Flush GDT + gdt_flush((uint64_t)&gdtPtr); +} + +// Global GDT instance +static GDT globalGDT; + +// C-compatible wrapper function +extern "C" { + +void gdt_init(void) { + globalGDT.init(); +} + +} // extern "C" diff --git a/kernel/src/interrupts.c b/kernel/src/interrupts.cpp similarity index 99% rename from kernel/src/interrupts.c rename to kernel/src/interrupts.cpp index e4d6151..ba1ff88 100644 --- a/kernel/src/interrupts.c +++ b/kernel/src/interrupts.cpp @@ -1,3 +1,4 @@ +// THIS IS C++ NOW /* * MetalOS Kernel - Interrupt Handling * diff --git a/kernel/src/main.c b/kernel/src/main.cpp similarity index 99% rename from kernel/src/main.c rename to kernel/src/main.cpp index 114ad30..ff0a09d 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.cpp @@ -1,3 +1,4 @@ +// THIS IS C++ NOW /* * MetalOS Kernel - Main Entry Point * diff --git a/kernel/src/memory.c b/kernel/src/memory.cpp similarity index 50% rename from kernel/src/memory.c rename to kernel/src/memory.cpp index 5c9dd77..e500827 100644 --- a/kernel/src/memory.c +++ b/kernel/src/memory.cpp @@ -7,45 +7,41 @@ #include "kernel/memory.h" -// Physical memory bitmap -#define PAGE_SIZE 4096 +// Physical memory bitmap constants #define BITMAP_SIZE 32768 // Supports up to 128MB with 4KB pages -static uint8_t page_bitmap[BITMAP_SIZE]; -static uint64_t total_pages = 0; -static uint64_t used_pages = 0; +// PhysicalMemoryManager class implementation +PhysicalMemoryManager::PhysicalMemoryManager() + : totalPages(0), usedPages(0) { + for (uint64_t i = 0; i < BITMAP_SIZE; i++) { + pageBitmap[i] = 0; + } +} -// Heap for kernel allocations -static uint8_t* heap_start = NULL; -static uint8_t* heap_current = NULL; -static uint8_t* heap_end = NULL; - -// Initialize physical memory manager -void pmm_init(BootInfo* boot_info) { - (void)boot_info; // TODO: Parse UEFI memory map +void PhysicalMemoryManager::init(BootInfo* bootInfo) { + (void)bootInfo; // TODO: Parse UEFI memory map // For now, assume 128MB of usable memory starting at 16MB - total_pages = (128 * 1024 * 1024) / PAGE_SIZE; + totalPages = (128 * 1024 * 1024) / PAGE_SIZE; // Clear bitmap for (uint64_t i = 0; i < BITMAP_SIZE; i++) { - page_bitmap[i] = 0; + pageBitmap[i] = 0; } - used_pages = 0; + usedPages = 0; } -// Allocate a physical page -void* pmm_alloc_page(void) { +void* PhysicalMemoryManager::allocPage() { // Find first free page in bitmap - for (uint64_t i = 0; i < total_pages; i++) { + for (uint64_t i = 0; i < totalPages; i++) { uint64_t byte = i / 8; uint64_t bit = i % 8; - if (!(page_bitmap[byte] & (1 << bit))) { + if (!(pageBitmap[byte] & (1 << bit))) { // Mark as used - page_bitmap[byte] |= (1 << bit); - used_pages++; + pageBitmap[byte] |= (1 << bit); + usedPages++; // Return physical address // Assuming memory starts at 16MB @@ -54,68 +50,66 @@ void* pmm_alloc_page(void) { } // Out of memory - return NULL; + return nullptr; } -// Free a physical page -void pmm_free_page(void* page) { +void PhysicalMemoryManager::freePage(void* page) { uint64_t addr = (uint64_t)page; // Calculate page index - uint64_t page_idx = (addr - 0x01000000UL) / PAGE_SIZE; + uint64_t pageIdx = (addr - 0x01000000UL) / PAGE_SIZE; - if (page_idx >= total_pages) { + if (pageIdx >= totalPages) { return; // Invalid address } - uint64_t byte = page_idx / 8; - uint64_t bit = page_idx % 8; + uint64_t byte = pageIdx / 8; + uint64_t bit = pageIdx % 8; // Mark as free - page_bitmap[byte] &= ~(1 << bit); - used_pages--; + pageBitmap[byte] &= ~(1 << bit); + usedPages--; } -// Get total memory -uint64_t pmm_get_total_memory(void) { - return total_pages * PAGE_SIZE; +uint64_t PhysicalMemoryManager::getTotalMemory() const { + return totalPages * PAGE_SIZE; } -// Get free memory -uint64_t pmm_get_free_memory(void) { - return (total_pages - used_pages) * PAGE_SIZE; +uint64_t PhysicalMemoryManager::getFreeMemory() const { + return (totalPages - usedPages) * PAGE_SIZE; } -// Initialize heap allocator -void heap_init(void* start, size_t size) { - heap_start = (uint8_t*)start; - heap_current = heap_start; - heap_end = heap_start + size; +// HeapAllocator class implementation +HeapAllocator::HeapAllocator() + : heapStart(nullptr), heapCurrent(nullptr), heapEnd(nullptr) {} + +void HeapAllocator::init(void* start, size_t size) { + heapStart = (uint8_t*)start; + heapCurrent = heapStart; + heapEnd = heapStart + size; } -// Simple bump allocator (no free support in this version) -void* kmalloc(size_t size) { - if (!heap_start) { - return NULL; +void* HeapAllocator::alloc(size_t size) { + if (!heapStart) { + return nullptr; } // Align to 16 bytes size = (size + 15) & ~15; - if (heap_current + size > heap_end) { - return NULL; // Out of heap memory + if (heapCurrent + size > heapEnd) { + return nullptr; // Out of heap memory } - void* ptr = heap_current; - heap_current += size; + void* ptr = heapCurrent; + heapCurrent += size; return ptr; } -// Allocate and zero memory -void* kcalloc(size_t num, size_t size) { +void* HeapAllocator::calloc(size_t num, size_t size) { size_t total = num * size; - void* ptr = kmalloc(total); + void* ptr = alloc(total); if (ptr) { memset(ptr, 0, total); @@ -124,15 +118,13 @@ void* kcalloc(size_t num, size_t size) { return ptr; } -// Free memory (not implemented in bump allocator) -void kfree(void* ptr) { +void HeapAllocator::free(void* ptr) { (void)ptr; // TODO: Implement proper free with a real allocator // For now, bump allocator doesn't support freeing } // Memory utility functions - void* memset(void* dest, int val, size_t count) { uint8_t* d = (uint8_t*)dest; uint8_t v = (uint8_t)val; @@ -167,3 +159,48 @@ int memcmp(const void* s1, const void* s2, size_t count) { return 0; } + +// Global instances +static PhysicalMemoryManager globalPMM; +static HeapAllocator globalHeap; + +// C-compatible wrapper functions +extern "C" { + +void pmm_init(BootInfo* boot_info) { + globalPMM.init(boot_info); +} + +void* pmm_alloc_page(void) { + return globalPMM.allocPage(); +} + +void pmm_free_page(void* page) { + globalPMM.freePage(page); +} + +uint64_t pmm_get_total_memory(void) { + return globalPMM.getTotalMemory(); +} + +uint64_t pmm_get_free_memory(void) { + return globalPMM.getFreeMemory(); +} + +void heap_init(void* start, size_t size) { + globalHeap.init(start, size); +} + +void* kmalloc(size_t size) { + return globalHeap.alloc(size); +} + +void* kcalloc(size_t num, size_t size) { + return globalHeap.calloc(num, size); +} + +void kfree(void* ptr) { + globalHeap.free(ptr); +} + +} // extern "C" diff --git a/kernel/src/pci.c b/kernel/src/pci.cpp similarity index 52% rename from kernel/src/pci.c rename to kernel/src/pci.cpp index 41f6638..3f96bcc 100644 --- a/kernel/src/pci.c +++ b/kernel/src/pci.cpp @@ -19,13 +19,10 @@ static inline uint32_t inl(uint16_t port) { return value; } -// Maximum devices we'll track -#define MAX_PCI_DEVICES 256 -static pci_device_t pci_devices[MAX_PCI_DEVICES]; -static uint32_t pci_device_count = 0; +// PCIManager class implementation +PCIManager::PCIManager() : deviceCount(0) {} -// Read from PCI configuration space -uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) { +uint32_t PCIManager::readConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) { uint32_t address = (uint32_t)( ((uint32_t)bus << 16) | ((uint32_t)device << 11) | @@ -38,8 +35,7 @@ uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t return inl(PCI_CONFIG_DATA); } -// Write to PCI configuration space -void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) { +void PCIManager::writeConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) { uint32_t address = (uint32_t)( ((uint32_t)bus << 16) | ((uint32_t)device << 11) | @@ -52,11 +48,10 @@ void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t off outl(PCI_CONFIG_DATA, value); } -// Probe a PCI device -static void pci_probe_device(uint8_t bus, uint8_t device, uint8_t function) { - uint32_t vendor_device = pci_read_config(bus, device, function, 0x00); - uint16_t vendor_id = vendor_device & 0xFFFF; - uint16_t device_id = (vendor_device >> 16) & 0xFFFF; +void PCIManager::probeDevice(uint8_t bus, uint8_t device, uint8_t function) { + uint32_t vendorDevice = readConfig(bus, device, function, 0x00); + uint16_t vendor_id = vendorDevice & 0xFFFF; + uint16_t device_id = (vendorDevice >> 16) & 0xFFFF; // Check if device exists if (vendor_id == 0xFFFF) { @@ -64,15 +59,15 @@ static void pci_probe_device(uint8_t bus, uint8_t device, uint8_t function) { } // Read class code - uint32_t class_rev = pci_read_config(bus, device, function, 0x08); - uint8_t class_code = (class_rev >> 24) & 0xFF; - uint8_t subclass = (class_rev >> 16) & 0xFF; - uint8_t prog_if = (class_rev >> 8) & 0xFF; - uint8_t revision_id = class_rev & 0xFF; + uint32_t classRev = readConfig(bus, device, function, 0x08); + uint8_t class_code = (classRev >> 24) & 0xFF; + uint8_t subclass = (classRev >> 16) & 0xFF; + uint8_t prog_if = (classRev >> 8) & 0xFF; + uint8_t revision_id = classRev & 0xFF; // Store device info - if (pci_device_count < MAX_PCI_DEVICES) { - pci_device_t* dev = &pci_devices[pci_device_count++]; + if (deviceCount < MAX_PCI_DEVICES) { + PCIDevice* dev = &devices[deviceCount++]; dev->bus = bus; dev->device = device; dev->function = function; @@ -85,68 +80,86 @@ static void pci_probe_device(uint8_t bus, uint8_t device, uint8_t function) { // Read BARs (Base Address Registers) for (int i = 0; i < 6; i++) { - dev->bar[i] = pci_read_config(bus, device, function, 0x10 + (i * 4)); + dev->bar[i] = readConfig(bus, device, function, 0x10 + (i * 4)); } } } -// Initialize PCI subsystem -void pci_init(void) { +void PCIManager::init() { + deviceCount = 0; + // Scan all buses, devices, and functions - // Note: On real hardware, could optimize by stopping after consecutive empty buses for (uint16_t bus = 0; bus < 256; bus++) { - uint8_t devices_found = 0; - for (uint8_t device = 0; device < 32; device++) { // Check if device exists (function 0) - uint32_t vendor_device = pci_read_config(bus, device, 0, 0x00); - if ((vendor_device & 0xFFFF) == 0xFFFF) { + uint32_t vendorDevice = readConfig(bus, device, 0, 0x00); + if ((vendorDevice & 0xFFFF) == 0xFFFF) { continue; // Device doesn't exist } - devices_found++; - pci_probe_device(bus, device, 0); + probeDevice(bus, device, 0); // Check if multi-function device - uint32_t header_type = pci_read_config(bus, device, 0, 0x0C); - if (header_type & 0x00800000) { + uint32_t headerType = readConfig(bus, device, 0, 0x0C); + if (headerType & 0x00800000) { // Multi-function device, scan other functions for (uint8_t function = 1; function < 8; function++) { - vendor_device = pci_read_config(bus, device, function, 0x00); - if ((vendor_device & 0xFFFF) != 0xFFFF) { - pci_probe_device(bus, device, function); + vendorDevice = readConfig(bus, device, function, 0x00); + if ((vendorDevice & 0xFFFF) != 0xFFFF) { + probeDevice(bus, device, function); } } } } - - // Early termination: if no devices found in this bus and we're past bus 0, - // we can potentially stop (though some systems have gaps) - // For now, continue full scan for maximum compatibility } } -// Find a PCI device by vendor and device ID -pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id) { - for (uint32_t i = 0; i < pci_device_count; i++) { - if (pci_devices[i].vendor_id == vendor_id && - pci_devices[i].device_id == device_id) { - return &pci_devices[i]; +PCIDevice* PCIManager::findDevice(uint16_t vendor_id, uint16_t device_id) { + for (uint32_t i = 0; i < deviceCount; i++) { + if (devices[i].vendor_id == vendor_id && devices[i].device_id == device_id) { + return &devices[i]; } } - return NULL; + return nullptr; } -// Enable bus mastering for a device -void pci_enable_bus_mastering(pci_device_t* dev) { +void PCIManager::enableBusMastering(PCIDevice* dev) { if (!dev) return; // Read command register (offset 0x04) - uint32_t command = pci_read_config(dev->bus, dev->device, dev->function, 0x04); + uint32_t command = readConfig(dev->bus, dev->device, dev->function, 0x04); // Set bus master bit (bit 2) command |= 0x04; // Write back - pci_write_config(dev->bus, dev->device, dev->function, 0x04, command); + writeConfig(dev->bus, dev->device, dev->function, 0x04, command); } + +// Global PCI manager instance +static PCIManager globalPCI; + +// C-compatible wrapper functions +extern "C" { + +void pci_init(void) { + globalPCI.init(); +} + +uint32_t pci_read_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset) { + return globalPCI.readConfig(bus, device, function, offset); +} + +void pci_write_config(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value) { + globalPCI.writeConfig(bus, device, function, offset, value); +} + +pci_device_t* pci_find_device(uint16_t vendor_id, uint16_t device_id) { + return reinterpret_cast(globalPCI.findDevice(vendor_id, device_id)); +} + +void pci_enable_bus_mastering(pci_device_t* dev) { + globalPCI.enableBusMastering(reinterpret_cast(dev)); +} + +} // extern "C" diff --git a/kernel/src/smp.c b/kernel/src/smp.cpp similarity index 99% rename from kernel/src/smp.c rename to kernel/src/smp.cpp index d0b9eb7..94a4614 100644 --- a/kernel/src/smp.c +++ b/kernel/src/smp.cpp @@ -1,3 +1,4 @@ +// THIS IS C++ NOW /* * MetalOS Kernel - SMP (Symmetric Multi-Processing) Support * diff --git a/kernel/src/spinlock.c b/kernel/src/spinlock.cpp similarity index 58% rename from kernel/src/spinlock.c rename to kernel/src/spinlock.cpp index 40086b2..da8817a 100644 --- a/kernel/src/spinlock.c +++ b/kernel/src/spinlock.cpp @@ -7,19 +7,21 @@ #include "kernel/spinlock.h" -// Initialize spinlock -void spinlock_init(spinlock_t* lock) { - lock->lock = 0; +// Spinlock class implementation + +Spinlock::Spinlock() : lock(0) {} + +void Spinlock::init() { + lock = 0; } -// Acquire spinlock (blocking) -void spinlock_acquire(spinlock_t* lock) { +void Spinlock::acquire() { while (1) { // Try to acquire lock using atomic exchange uint32_t old_value; __asm__ volatile( "xchgl %0, %1" - : "=r"(old_value), "+m"(lock->lock) + : "=r"(old_value), "+m"(lock) : "0"(1) : "memory" ); @@ -34,7 +36,55 @@ void spinlock_acquire(spinlock_t* lock) { } } -// Try to acquire spinlock (non-blocking) +bool Spinlock::tryAcquire() { + uint32_t old_value; + __asm__ volatile( + "xchgl %0, %1" + : "=r"(old_value), "+m"(lock) + : "0"(1) + : "memory" + ); + + return (old_value == 0); +} + +void Spinlock::release() { + // Memory barrier to ensure all previous stores are visible + __asm__ volatile("" ::: "memory"); + + // Release the lock + lock = 0; +} + +bool Spinlock::isLocked() const { + return lock != 0; +} + +// C-compatible wrapper functions for backward compatibility +extern "C" { + +void spinlock_init(spinlock_t* lock) { + lock->lock = 0; +} + +void spinlock_acquire(spinlock_t* lock) { + while (1) { + uint32_t old_value; + __asm__ volatile( + "xchgl %0, %1" + : "=r"(old_value), "+m"(lock->lock) + : "0"(1) + : "memory" + ); + + if (old_value == 0) { + return; + } + + __asm__ volatile("pause" ::: "memory"); + } +} + bool spinlock_try_acquire(spinlock_t* lock) { uint32_t old_value; __asm__ volatile( @@ -47,16 +97,13 @@ bool spinlock_try_acquire(spinlock_t* lock) { return (old_value == 0); } -// Release spinlock void spinlock_release(spinlock_t* lock) { - // Memory barrier to ensure all previous stores are visible __asm__ volatile("" ::: "memory"); - - // Release the lock lock->lock = 0; } -// Check if locked bool spinlock_is_locked(spinlock_t* lock) { return lock->lock != 0; } + +} // extern "C" diff --git a/kernel/src/timer.c b/kernel/src/timer.cpp similarity index 68% rename from kernel/src/timer.c rename to kernel/src/timer.cpp index ecd89e8..80d3596 100644 --- a/kernel/src/timer.c +++ b/kernel/src/timer.cpp @@ -15,9 +15,6 @@ // PIT constants #define PIT_BASE_FREQUENCY 1193182 // Hz -// Tick counter -static volatile uint64_t timer_ticks = 0; - // I/O port access functions static inline void outb(uint16_t port, uint8_t value) { __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); @@ -29,8 +26,10 @@ static inline uint8_t inb(uint16_t port) { return value; } -// Initialize timer -void timer_init(uint32_t frequency) { +// Timer class implementation +Timer::Timer() : ticks(0) {} + +void Timer::init(uint32_t frequency) { // Calculate divisor uint32_t divisor = PIT_BASE_FREQUENCY / frequency; @@ -46,22 +45,45 @@ void timer_init(uint32_t frequency) { uint8_t mask = inb(PIC1_DATA); mask &= ~0x01; // Clear bit 0 (IRQ0) outb(PIC1_DATA, mask); + + ticks = 0; } -// Get current tick count -uint64_t timer_get_ticks(void) { - return timer_ticks; +uint64_t Timer::getTicks() const { + return ticks; } -// Wait for specified number of ticks -void timer_wait(uint32_t ticks) { - uint64_t target = timer_ticks + ticks; - while (timer_ticks < target) { +void Timer::wait(uint32_t waitTicks) const { + uint64_t target = ticks + waitTicks; + while (ticks < target) { __asm__ volatile("hlt"); } } -// Timer interrupt handler -void timer_handler(void) { - timer_ticks++; +void Timer::handleInterrupt() { + ticks++; } + +// Global timer instance +static Timer globalTimer; + +// C-compatible wrapper functions +extern "C" { + +void timer_init(uint32_t frequency) { + globalTimer.init(frequency); +} + +uint64_t timer_get_ticks(void) { + return globalTimer.getTicks(); +} + +void timer_wait(uint32_t ticks) { + globalTimer.wait(ticks); +} + +void timer_handler(void) { + globalTimer.handleInterrupt(); +} + +} // extern "C"