diff --git a/.gitignore b/.gitignore index da338fb..7fc14b2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,6 @@ Makefile cmake-build-* target .venv -*cache* +__pycache__ .amazonq *backup \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index bf1e283..9507b40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,17 @@ cmake_minimum_required(VERSION 3.20) project(VoidFrame VERSION 0.0.2 LANGUAGES C CXX ASM_NASM) enable_language(ASM_NASM) +# ============================================================================ +# Module Path & Includes +# ============================================================================ +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +include(cache) +include(features) +include(variable) +include(dependencies) +include(flags) +include(configuration) + # ============================================================================ # Platform Checks # ============================================================================ @@ -37,6 +48,7 @@ message(STATUS "CMake Current Source Directory: ${CMAKE_CURRENT_SOURCE_DIR}") message(STATUS "CMake Current Binary Directory: ${CMAKE_CURRENT_BINARY_DIR}") message(STATUS "CMake Host System Name: ${CMAKE_HOST_SYSTEM_NAME}") message(STATUS "CMake Host System Processor: ${CMAKE_HOST_SYSTEM_PROCESSOR}") +message(STATUS "VoidFrame Scheduler: ${VF_SCHEDULER}") # ============================================================================ # Standard Configuration @@ -46,16 +58,6 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# ============================================================================ -# Module Path & Includes -# ============================================================================ -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") -include(features) -include(variable) -include(dependencies) -include(flags) -include(configuration) - # ============================================================================ # Source Files Organization # ============================================================================ @@ -77,6 +79,7 @@ set(KERNEL_CORE_SOURCES set(SCHED_SOURCES kernel/sched/MLFQ.c + kernel/sched/EEVDF.c ) set(KERNEL_ETC_SOURCES diff --git a/cmake/cache.cmake b/cmake/cache.cmake new file mode 100644 index 0000000..28e9072 --- /dev/null +++ b/cmake/cache.cmake @@ -0,0 +1,5 @@ +# ============================================================================ +# Cache variables +# ============================================================================ +set(VF_SCHEDULER "MLFQ" CACHE STRING "Scheduler type: MLFQ or EEVDF") +set_property(CACHE VF_SCHEDULER PROPERTY STRINGS MLFQ EEVDF) diff --git a/cmake/features.cmake b/cmake/features.cmake index 4f43682..7d9cf17 100644 --- a/cmake/features.cmake +++ b/cmake/features.cmake @@ -23,7 +23,6 @@ add_compile_definitions( VF_CONFIG_USE_ASTRA VF_CONFIG_USE_CERBERUS VF_CONFIG_CERBERUS_STACK_PROTECTION - VF_CONFIG_SCHED_MLFQ VF_CONFIG_INTEL ) @@ -41,4 +40,12 @@ endif() if(AUTOMATIC_POST) add_compile_definitions(VF_CONFIG_AUTOMATIC_POST) +endif() + +if(VF_SCHEDULER STREQUAL "MLFQ") + add_compile_definitions(VF_CONFIG_SCHED_MLFQ) +elseif(VF_SCHEDULER STREQUAL "EEVDF") + add_compile_definitions(VF_CONFIG_SCHED_EEVDF) +else() + message(FATAL_ERROR "Invalid scheduler: ${VF_SCHEDULER}. Have you pass: -DVF_SCHEDULER=?.") endif() \ No newline at end of file diff --git a/include/Scheduler.h b/include/Scheduler.h index a7df890..6c71b78 100644 --- a/include/Scheduler.h +++ b/include/Scheduler.h @@ -3,21 +3,31 @@ #ifndef VOIDFRAME_SCHEDULER_H #define VOIDFRAME_SCHEDULER_H #include "MLFQ.h" +#include "EEVDF.h" +#include "Shared.h" +// Initialize the active scheduler static inline __attribute__((always_inline)) int SchedulerInit() { #ifdef VF_CONFIG_SCHED_MLFQ return MLFQSchedInit(); #endif +#ifdef VF_CONFIG_SCHED_EEVDF + return EEVDFSchedInit(); +#endif #ifdef VF_CONFIG_SCHED_CFS return 0; // not implemented #endif return -1; } +// Create a new process static inline __attribute__((always_inline)) uint32_t CreateProcess(const char * name, void (*entry_point)()) { #ifdef VF_CONFIG_SCHED_MLFQ return MLFQCreateProcess(name ,entry_point); #endif +#ifdef VF_CONFIG_SCHED_EEVDF + return EEVDFCreateProcess(name, entry_point); +#endif #ifdef VF_CONFIG_SCHED_CFS return 0; // not implemented #endif @@ -25,64 +35,85 @@ static inline __attribute__((always_inline)) uint32_t CreateProcess(const char * } static inline __attribute__((always_inline)) -#if defined(VF_CONFIG_SCHED_MLFQ) -MLFQProcessControlBlock* -#elif defined(VF_CONFIG_SCHED_CFS) -void // not implemented -#else -void -#endif -GetCurrentProcess() { #ifdef VF_CONFIG_SCHED_MLFQ - return MLFQGetCurrentProcess(); +MLFQProcessControlBlock * +#endif +#ifdef VF_CONFIG_SCHED_EEVDF +EEVDFProcessControlBlock * #endif #ifdef VF_CONFIG_SCHED_CFS - return; // not implemented +void * #endif -} - -static inline __attribute__((always_inline)) -#if defined(VF_CONFIG_SCHED_MLFQ) -MLFQProcessControlBlock* -#elif defined(VF_CONFIG_SCHED_CFS) -void // not implemented -#else -void -#endif -GetProcessByPID(uint32_t pid) { +GetCurrentProcess() { #ifdef VF_CONFIG_SCHED_MLFQ - return MLFQGetCurrentProcessByPID(pid); + return MLFQGetCurrentProcess(); +#endif +#ifdef VF_CONFIG_SCHED_EEVDF + return EEVDFGetCurrentProcess(); #endif #ifdef VF_CONFIG_SCHED_CFS - return; // not implemented + return NULL; #endif } +// Yield CPU static inline __attribute__((always_inline)) void Yield() { #ifdef VF_CONFIG_SCHED_MLFQ return MLFQYield(); #endif +#ifdef VF_CONFIG_SCHED_EEVDF + return EEVDFYield(); +#endif #ifdef VF_CONFIG_SCHED_CFS return; // not implemented #endif } +// Main scheduler function (called from interrupt handler) static inline __attribute__((always_inline)) void Schedule(Registers* regs) { #ifdef VF_CONFIG_SCHED_MLFQ return MLFQSchedule(regs); #endif +#ifdef VF_CONFIG_SCHED_EEVDF + return EEVDFSchedule(regs); +#endif #ifdef VF_CONFIG_SCHED_CFS return; // not implemented #endif } +// Kill a process static inline __attribute__((always_inline)) void KillProcess(uint32_t pid) { #ifdef VF_CONFIG_SCHED_MLFQ return MLFQKillProcess(pid); #endif +#ifdef VF_CONFIG_SCHED_EEVDF + return EEVDFKillProcess(pid); +#endif #ifdef VF_CONFIG_SCHED_CFS return; // not implemented #endif } +// Scheduler-specific PCB access (for when you need the full scheduler-specific data) +#ifdef VF_CONFIG_SCHED_MLFQ +typedef MLFQProcessControlBlock SchedulerSpecificPCB; +static inline MLFQProcessControlBlock* GetMLFQCurrentProcess() { + return MLFQGetCurrentProcess(); +} +static inline MLFQProcessControlBlock* GetMLFQProcessByPID(uint32_t pid) { + return MLFQGetCurrentProcessByPID(pid); +} +#endif + +#ifdef VF_CONFIG_SCHED_EEVDF +typedef EEVDFProcessControlBlock SchedulerSpecificPCB; +static inline EEVDFProcessControlBlock* GetEEVDFCurrentProcess() { + return EEVDFGetCurrentProcess(); +} +static inline EEVDFProcessControlBlock* GetEEVDFProcessByPID(uint32_t pid) { + return EEVDFGetCurrentProcessByPID(pid); +} +#endif + #endif // VOIDFRAME_SCHEDULER_H diff --git a/kernel/sched/EEVDF.c b/kernel/sched/EEVDF.c new file mode 100644 index 0000000..076b631 --- /dev/null +++ b/kernel/sched/EEVDF.c @@ -0,0 +1,1098 @@ +#include "EEVDF.h" + +#include "APIC.h" +#include "Atomics.h" +#include "Cerberus.h" +#include "Compositor.h" +#include "KernelHeap.h" +#ifdef VF_CONFIG_USE_CERBERUS +#include "Cerberus.h" +#endif +#include "Console.h" +#include "Format.h" +#include "Io.h" +#include "Ipc.h" +#include "MemOps.h" +#include "Panic.h" +#include "Spinlock.h" +#include "VFS.h" +#include "VMem.h" +#include "x64.h" + +#define offsetof(type, member) ((uint64_t)&(((type*)0)->member)) + +// Performance optimizations +#define LIKELY(x) __builtin_expect(!!(x), 1) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#define CACHE_LINE_SIZE 64 +#define ALIGNED_CACHE __attribute__((aligned(CACHE_LINE_SIZE))) + +// Security constants +static const uint64_t EEVDF_SECURITY_MAGIC = 0x5EC0DE4D41474943ULL; +static const uint64_t EEVDF_SECURITY_SALT = 0xDEADBEEFCAFEBABEULL; +static const uint32_t EEVDF_MAX_SECURITY_VIOLATIONS = EEVDF_SECURITY_VIOLATION_LIMIT; + +// Nice-to-weight conversion tables (based on Linux CFS) +const uint32_t eevdf_nice_to_weight[40] = { + /* -20 */ 88761, 71755, 56483, 46273, 36291, + /* -15 */ 29154, 23254, 18705, 14949, 11916, + /* -10 */ 9548, 7620, 6100, 4904, 3906, + /* -5 */ 3121, 2501, 1991, 1586, 1277, + /* 0 */ 1024, 820, 655, 526, 423, + /* 5 */ 335, 272, 215, 172, 137, + /* 10 */ 110, 87, 70, 56, 45, + /* 15 */ 36, 29, 23, 18, 15, +}; + +const uint32_t eevdf_nice_to_wmult[40] = { + /* -20 */ 48388, 59856, 76040, 92818, 118348, + /* -15 */ 147320, 184698, 229616, 287308, 360437, + /* -10 */ 449829, 563644, 704093, 875809, 1099582, + /* -5 */ 1376151, 1717300, 2157191, 2708050, 3363326, + /* 0 */ 4194304, 5237765, 6557202, 8165337, 10153587, + /* 5 */ 12820798, 15790321, 19976592, 24970740, 31350126, + /* 10 */ 39045157, 49367440, 61356676, 76695844, 95443717, + /* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153, +}; + +// Global state +static EEVDFProcessControlBlock processes[EEVDF_MAX_PROCESSES] ALIGNED_CACHE; +static volatile uint32_t next_pid = 1; +static uint64_t pid_bitmap[EEVDF_MAX_PROCESSES / 64 + 1] = {0}; +static volatile irq_flags_t pid_lock = 0; +static volatile uint32_t current_process = 0; +static volatile uint32_t process_count = 0; +static volatile int need_schedule = 0; +static volatile int scheduler_lock = 0; +rwlock_t process_table_rwlock_eevdf = {0}; + +// Security subsystem +uint32_t eevdf_security_manager_pid = 0; +static uint32_t security_violation_count = 0; +static uint64_t last_security_check = 0; + +// Fast bitmap operations for process slots +static uint64_t active_process_bitmap = 0; +static uint64_t ready_process_bitmap = 0; + +// Main scheduler instance +static EEVDFScheduler eevdf_scheduler ALIGNED_CACHE; +static EEVDFRBNode rb_node_pool[EEVDF_MAX_PROCESSES] ALIGNED_CACHE; +static uint32_t rb_node_pool_bitmap[(EEVDF_MAX_PROCESSES + 31) / 32]; + +// Lockless termination queue +static volatile uint32_t termination_queue[EEVDF_MAX_PROCESSES]; +static volatile uint32_t term_queue_head = 0; +static volatile uint32_t term_queue_tail = 0; +static volatile uint32_t term_queue_count = 0; + +// Performance counters +static uint64_t context_switches = 0; +static uint64_t scheduler_calls = 0; + +extern volatile uint32_t APIC_HZ; +extern volatile uint32_t APICticks; + +// ============================================================================= +// Utility Functions +// ============================================================================= + +static inline int FastFFS(const uint64_t value) { + return __builtin_ctzll(value); +} + +static inline int FastCLZ(const uint64_t value) { + return __builtin_clzll(value); +} + +static inline uint64_t GetNS(void) { + // Convert APIC ticks to nanoseconds + // Assuming APIC_HZ is in Hz, convert to ns + return (APICticks * 1000000000ULL) / APIC_HZ; +} + +uint64_t EEVDFGetNanoseconds(void) { + return GetNS(); +} + +uint64_t EEVDFGetSystemTicks(void) { + return APICticks; +} + +// ============================================================================= +// Nice Level Functions +// ============================================================================= + +uint32_t EEVDFNiceToWeight(int nice) { + if (nice < EEVDF_MIN_NICE) nice = EEVDF_MIN_NICE; + if (nice > EEVDF_MAX_NICE) nice = EEVDF_MAX_NICE; + return eevdf_nice_to_weight[nice - EEVDF_MIN_NICE]; +} + +uint32_t EEVDFNiceToWmult(int nice) { + if (nice < EEVDF_MIN_NICE) nice = EEVDF_MIN_NICE; + if (nice > EEVDF_MAX_NICE) nice = EEVDF_MAX_NICE; + return eevdf_nice_to_wmult[nice - EEVDF_MIN_NICE]; +} + +void EEVDFSetTaskNice(EEVDFProcessControlBlock* p, int nice) { + if (!p) return; + + if (nice < EEVDF_MIN_NICE) nice = EEVDF_MIN_NICE; + if (nice > EEVDF_MAX_NICE) nice = EEVDF_MAX_NICE; + + p->nice = nice; + p->weight = EEVDFNiceToWeight(nice); + p->inv_weight = EEVDFNiceToWmult(nice); +} + +// ============================================================================= +// Virtual Time Calculations +// ============================================================================= + +uint64_t EEVDFCalcDelta(uint64_t delta_exec, uint32_t weight, uint32_t lw) { + if (lw == 0) { + lw = EEVDF_NICE_0_LOAD; + } + uint64_t fact = (weight << 16) / lw; // Shifted for precision + return (delta_exec * fact) >> 16; +} + +uint64_t EEVDFCalcSlice(EEVDFRunqueue* rq, EEVDFProcessControlBlock* se) { + uint32_t nr_running = rq->nr_running; + if (nr_running == 0) return EEVDF_TIME_SLICE_NS; + + uint64_t slice = (EEVDF_TARGET_LATENCY * se->weight) / rq->load_weight; + + // Ensure minimum granularity + if (slice < EEVDF_MIN_GRANULARITY) { + slice = EEVDF_MIN_GRANULARITY; + } + + // Cap maximum slice + if (slice > EEVDF_MAX_TIME_SLICE_NS) { + slice = EEVDF_MAX_TIME_SLICE_NS; + } + + return slice; +} + +void EEVDFUpdateCurr(EEVDFRunqueue* rq, EEVDFProcessControlBlock* curr) { + uint64_t now = GetNS(); + uint64_t delta_exec = now - curr->exec_start; + + if (delta_exec == 0) return; + + curr->exec_start = now; + curr->sum_exec_runtime += delta_exec; + curr->cpu_time_accumulated += delta_exec; + + // Update vruntime + uint64_t delta_fair = EEVDFCalcDelta(delta_exec, EEVDF_NICE_0_LOAD, rq->load_weight); + curr->vruntime += delta_fair; + + // Update runqueue minimum vruntime + if (rq->rb_leftmost) { + EEVDFProcessControlBlock* leftmost = &processes[rq->rb_leftmost->slot]; + rq->min_vruntime = leftmost->vruntime; + } else { + rq->min_vruntime = curr->vruntime; + } +} + +// ============================================================================= +// Red-Black Tree Operations +// ============================================================================= + +static void EEVDFRBNodeInit(EEVDFRBNode* node, uint32_t slot) { + node->left = NULL; + node->right = NULL; + node->parent = NULL; + node->color = 1; // Red + node->slot = slot; +} + +static EEVDFRBNode* EEVDFAllocRBNode(uint32_t slot) { + for (uint32_t i = 0; i < EEVDF_MAX_PROCESSES; i++) { + uint32_t word_idx = i / 32; + uint32_t bit_idx = i % 32; + + if (!(rb_node_pool_bitmap[word_idx] & (1U << bit_idx))) { + rb_node_pool_bitmap[word_idx] |= (1U << bit_idx); + EEVDFRBNode* node = &rb_node_pool[i]; + EEVDFRBNodeInit(node, slot); + return node; + } + } + return NULL; +} + +static void EEVDFFreeRBNode(EEVDFRBNode* node) { + if (!node) return; + + uint32_t index = node - rb_node_pool; + if (index >= EEVDF_MAX_PROCESSES) return; + + uint32_t word_idx = index / 32; + uint32_t bit_idx = index % 32; + + rb_node_pool_bitmap[word_idx] &= ~(1U << bit_idx); + node->left = node->right = node->parent = NULL; + node->color = 0; + node->slot = 0; +} + +// Red-black tree rotation operations +static void EEVDFRBRotateLeft(EEVDFRunqueue* rq, EEVDFRBNode* x) { + EEVDFRBNode* y = x->right; + x->right = y->left; + + if (y->left) y->left->parent = x; + y->parent = x->parent; + + if (!x->parent) { + rq->rb_root = y; + } else if (x == x->parent->left) { + x->parent->left = y; + } else { + x->parent->right = y; + } + + y->left = x; + x->parent = y; +} + +static void EEVDFRBRotateRight(EEVDFRunqueue* rq, EEVDFRBNode* y) { + EEVDFRBNode* x = y->left; + y->left = x->right; + + if (x->right) x->right->parent = y; + x->parent = y->parent; + + if (!y->parent) { + rq->rb_root = x; + } else if (y == y->parent->right) { + y->parent->right = x; + } else { + y->parent->left = x; + } + + x->right = y; + y->parent = x; +} + +// Red-black tree insertion fixup +static void EEVDFRBInsertFixup(EEVDFRunqueue* rq, EEVDFRBNode* z) { + while (z->parent && z->parent->color == 1) { // parent is red + if (z->parent == z->parent->parent->left) { + EEVDFRBNode* y = z->parent->parent->right; // uncle + if (y && y->color == 1) { // uncle is red + z->parent->color = 0; // black + y->color = 0; + z->parent->parent->color = 1; // red + z = z->parent->parent; + } else { + if (z == z->parent->right) { + z = z->parent; + EEVDFRBRotateLeft(rq, z); + } + z->parent->color = 0; + z->parent->parent->color = 1; + EEVDFRBRotateRight(rq, z->parent->parent); + } + } else { + EEVDFRBNode* y = z->parent->parent->left; // uncle + if (y && y->color == 1) { // uncle is red + z->parent->color = 0; + y->color = 0; + z->parent->parent->color = 1; + z = z->parent->parent; + } else { + if (z == z->parent->left) { + z = z->parent; + EEVDFRBRotateRight(rq, z); + } + z->parent->color = 0; + z->parent->parent->color = 1; + EEVDFRBRotateLeft(rq, z->parent->parent); + } + } + } + rq->rb_root->color = 0; // root is always black +} + +// Insert into red-black tree ordered by vruntime +static void EEVDFRBInsert(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p) { + EEVDFRBNode* node = EEVDFAllocRBNode(p - processes); + if (!node) return; + + p->rb_node = node; + + EEVDFRBNode* parent = NULL; + EEVDFRBNode** link = &rq->rb_root; + int leftmost = 1; + + // Find insertion point + while (*link) { + parent = *link; + EEVDFProcessControlBlock* entry = &processes[parent->slot]; + + if (p->vruntime < entry->vruntime) { + link = &parent->left; + } else { + link = &parent->right; + leftmost = 0; + } + } + + // Update leftmost pointer + if (leftmost) { + rq->rb_leftmost = node; + } + + // Insert node + node->parent = parent; + *link = node; + + EEVDFRBInsertFixup(rq, node); +} + +// Find minimum node (leftmost) +static EEVDFRBNode* EEVDFRBFirst(EEVDFRBNode* root) { + if (!root) return NULL; + + while (root->left) { + root = root->left; + } + return root; +} + +// Delete fixup for red-black tree +static void EEVDFRBDeleteFixup(EEVDFRunqueue* rq, EEVDFRBNode* x, EEVDFRBNode* parent) { + while (x != rq->rb_root && (!x || x->color == 0)) { + if (x == parent->left) { + EEVDFRBNode* w = parent->right; + if (w && w->color == 1) { + w->color = 0; + parent->color = 1; + EEVDFRBRotateLeft(rq, parent); + w = parent->right; + } + if (w && (!w->left || w->left->color == 0) && (!w->right || w->right->color == 0)) { + if (w) w->color = 1; + x = parent; + parent = x->parent; + } else { + if (w && (!w->right || w->right->color == 0)) { + if (w->left) w->left->color = 0; + w->color = 1; + EEVDFRBRotateRight(rq, w); + w = parent->right; + } + if (w) { + w->color = parent->color; + parent->color = 0; + if (w->right) w->right->color = 0; + } + EEVDFRBRotateLeft(rq, parent); + x = rq->rb_root; + } + } else { + EEVDFRBNode* w = parent->left; + if (w && w->color == 1) { + w->color = 0; + parent->color = 1; + EEVDFRBRotateRight(rq, parent); + w = parent->left; + } + if (w && (!w->right || w->right->color == 0) && (!w->left || w->left->color == 0)) { + if (w) w->color = 1; + x = parent; + parent = x->parent; + } else { + if (w && (!w->left || w->left->color == 0)) { + if (w->right) w->right->color = 0; + w->color = 1; + EEVDFRBRotateLeft(rq, w); + w = parent->left; + } + if (w) { + w->color = parent->color; + parent->color = 0; + if (w->left) w->left->color = 0; + } + EEVDFRBRotateRight(rq, parent); + x = rq->rb_root; + } + } + } + if (x) x->color = 0; +} + +// Remove from red-black tree +static void EEVDFRBDelete(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p) { + EEVDFRBNode* node = p->rb_node; + if (!node) return; + + // Update leftmost if necessary + if (rq->rb_leftmost == node) { + if (node->right) { + rq->rb_leftmost = EEVDFRBFirst(node->right); + } else { + rq->rb_leftmost = node->parent; + } + } + + EEVDFRBNode* y = node; + EEVDFRBNode* x; + EEVDFRBNode* x_parent; + uint8_t y_original_color = y->color; + + if (!node->left) { + x = node->right; + x_parent = node->parent; + if (!node->parent) { + rq->rb_root = node->right; + } else if (node == node->parent->left) { + node->parent->left = node->right; + } else { + node->parent->right = node->right; + } + if (node->right) node->right->parent = node->parent; + } else if (!node->right) { + x = node->left; + x_parent = node->parent; + if (!node->parent) { + rq->rb_root = node->left; + } else if (node == node->parent->left) { + node->parent->left = node->left; + } else { + node->parent->right = node->left; + } + node->left->parent = node->parent; + } else { + // Find successor + y = node->right; + while (y->left) y = y->left; + + y_original_color = y->color; + x = y->right; + x_parent = y->parent; + + if (y->parent == node) { + x_parent = y; + } else { + if (y->right) y->right->parent = y->parent; + y->parent->left = y->right; + y->right = node->right; + y->right->parent = y; + x_parent = y->parent; + } + + if (!node->parent) { + rq->rb_root = y; + } else if (node == node->parent->left) { + node->parent->left = y; + } else { + node->parent->right = y; + } + + y->parent = node->parent; + y->color = node->color; + y->left = node->left; + y->left->parent = y; + } + + if (y_original_color == 0) { + EEVDFRBDeleteFixup(rq, x, x_parent); + } + + EEVDFFreeRBNode(node); + p->rb_node = NULL; +} + +// ============================================================================= +// Task Queue Management +// ============================================================================= + +void EEVDFEnqueueTask(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p) { + if (!p || p->state != PROC_READY) return; + + // Place newly woken tasks at min_vruntime to ensure fairness + if (p->vruntime < rq->min_vruntime) { + p->vruntime = rq->min_vruntime; + } + + // Calculate deadline + p->deadline = p->vruntime + EEVDFCalcSlice(rq, p); + + // Update load + rq->load_weight += p->weight; + rq->nr_running++; + + // Insert into red-black tree + EEVDFRBInsert(rq, p); +} + +void EEVDFDequeueTask(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p) { + if (!p || !p->rb_node) return; + + // Update load + if (rq->load_weight >= p->weight) { + rq->load_weight -= p->weight; + } else { + rq->load_weight = 0; + } + + if (rq->nr_running > 0) { + rq->nr_running--; + } + + // Remove from red-black tree + EEVDFRBDelete(rq, p); +} + +EEVDFProcessControlBlock* EEVDFPickNext(EEVDFRunqueue* rq) { + if (!rq->rb_leftmost) return NULL; + + EEVDFProcessControlBlock* next = &processes[rq->rb_leftmost->slot]; + + // EEVDF: Pick earliest eligible with earliest deadline + // For simplicity, we pick the leftmost (earliest vruntime) + // A full EEVDF implementation would check eligibility based on current virtual time + + return next; +} + +// ============================================================================= +// Process Management (same security model as MLFQ) +// ============================================================================= + +static uint64_t EEVDFSecureHash(const void* data, const uint64_t len, uint64_t salt) { + const uint8_t* bytes = data; + uint64_t hash = salt; + + for (uint64_t i = 0; i < len; i++) { + hash ^= bytes[i]; + hash *= 0x100000001b3ULL; // FNV-1a prime + } + + return hash; +} + +static uint64_t EEVDFCalculateSecureChecksum(const EEVDFSecurityToken* token, uint32_t pid) { + uint64_t base_hash = EEVDFSecureHash(token, offsetof(EEVDFSecurityToken, checksum), EEVDF_SECURITY_SALT); + uint64_t pid_hash = EEVDFSecureHash(&pid, sizeof(pid), EEVDF_SECURITY_SALT); + return base_hash ^ pid_hash; +} + +static inline int FindFreeSlotFast(void) { + if (UNLIKELY(active_process_bitmap == ~1ULL)) { + return -1; + } + + uint64_t available = ~active_process_bitmap; + available &= ~1ULL; // Clear bit 0 + + if (UNLIKELY(available == 0)) { + return -1; + } + + int slot = FastFFS(available); + active_process_bitmap |= (1ULL << slot); + return slot; +} + +static inline void FreeSlotFast(int slot) { + if (LIKELY(slot > 0 && slot < 64)) { + active_process_bitmap &= ~(1ULL << slot); + } +} + +// Add to termination queue (same as MLFQ) +static void AddToTerminationQueueAtomic(uint32_t slot) { + uint32_t tail = term_queue_tail; + uint32_t new_tail = (tail + 1) % EEVDF_MAX_PROCESSES; + + if (UNLIKELY(term_queue_count >= EEVDF_MAX_PROCESSES)) { + PANIC("EEVDF: Termination queue overflow"); + } + + termination_queue[tail] = slot; + __atomic_thread_fence(__ATOMIC_SEQ_CST); + term_queue_tail = new_tail; + AtomicInc(&term_queue_count); +} + +static uint32_t RemoveFromTerminationQueueAtomic(void) { + if (UNLIKELY(term_queue_count == 0)) { + return EEVDF_MAX_PROCESSES; + } + + uint32_t head = term_queue_head; + uint32_t slot = termination_queue[head]; + + term_queue_head = (head + 1) % EEVDF_MAX_PROCESSES; + AtomicDec(&term_queue_count); + + return slot; +} + +void ProcessExitStubEEVDF() { + EEVDFProcessControlBlock* current = EEVDFGetCurrentProcess(); + + PrintKernel("\nEEVDF: Process PID "); + PrintKernelInt(current->pid); + PrintKernel(" exited normally\n"); + + // Terminate process + EEVDFKillCurrentProcess("Normal exit"); + + while (1) { + __asm__ __volatile__("hlt"); + } + __builtin_unreachable(); +} + +// ============================================================================= +// Core Scheduler Functions +// ============================================================================= + +void EEVDFUpdateClock(EEVDFRunqueue* rq) { + rq->clock = GetNS(); + rq->exec_clock = rq->clock; +} + +void EEVDFSchedule(Registers* regs) { + irq_flags_t flags = SpinLockIrqSave(&scheduler_lock); + + AtomicInc(&scheduler_calls); + AtomicInc(&eevdf_scheduler.tick_counter); + + EEVDFRunqueue* rq = &eevdf_scheduler.rq; + uint32_t old_slot = rq->current_slot; + EEVDFProcessControlBlock* prev = NULL; + + // Update clock + EEVDFUpdateClock(rq); + + // Handle current task + if (LIKELY(old_slot != 0 && old_slot < EEVDF_MAX_PROCESSES)) { + prev = &processes[old_slot]; + + if (UNLIKELY(prev->state == PROC_DYING || prev->state == PROC_ZOMBIE || prev->state == PROC_TERMINATED)) { + goto pick_next; + } + + // Save context + FastMemcpy(&prev->context, regs, sizeof(Registers)); + + // Update runtime statistics + EEVDFUpdateCurr(rq, prev); + + // Check if task should continue running + if (LIKELY(prev->state == PROC_RUNNING)) { + prev->state = PROC_READY; + ready_process_bitmap |= (1ULL << old_slot); + + // Re-enqueue if it still has time left and is still the best choice + uint64_t slice_ns = EEVDFCalcSlice(rq, prev); + uint64_t runtime = GetNS() - prev->exec_start; + + if (runtime < slice_ns) { + // Task still has time, but check if there's a better choice + EEVDFProcessControlBlock* next_best = EEVDFPickNext(rq); + if (next_best && next_best != prev) { + // There's a better task to run + EEVDFEnqueueTask(rq, prev); + } else { + // Continue running current task + prev->state = PROC_RUNNING; + ready_process_bitmap &= ~(1ULL << old_slot); + SpinUnlockIrqRestore(&scheduler_lock, flags); + return; + } + } else { + // Time slice expired, re-enqueue + EEVDFEnqueueTask(rq, prev); + } + } + } + +pick_next:; + EEVDFProcessControlBlock* next = EEVDFPickNext(rq); + uint32_t next_slot; + + if (UNLIKELY(!next)) { + next_slot = 0; // Idle process + } else { + next_slot = next - processes; + + if (UNLIKELY(next_slot >= EEVDF_MAX_PROCESSES || next->state != PROC_READY)) { + goto pick_next; + } + + // Dequeue the selected task + EEVDFDequeueTask(rq, next); + } + + // Context switch + rq->current_slot = next_slot; + current_process = next_slot; + + if (LIKELY(next_slot != 0)) { + EEVDFProcessControlBlock* new_proc = &processes[next_slot]; + new_proc->state = PROC_RUNNING; + ready_process_bitmap &= ~(1ULL << next_slot); + + new_proc->exec_start = GetNS(); + new_proc->slice_ns = EEVDFCalcSlice(rq, new_proc); + + FastMemcpy(regs, &new_proc->context, sizeof(Registers)); + AtomicInc(&context_switches); + eevdf_scheduler.switch_count++; + } + + SpinUnlockIrqRestore(&scheduler_lock, flags); +} + +int EEVDFSchedInit(void) { + // Initialize process array + FastMemset(processes, 0, sizeof(EEVDFProcessControlBlock) * EEVDF_MAX_PROCESSES); + + // Initialize scheduler + FastMemset(&eevdf_scheduler, 0, sizeof(EEVDFScheduler)); + + // Initialize RB tree node pool + FastMemset(rb_node_pool, 0, sizeof(rb_node_pool)); + FastMemset(rb_node_pool_bitmap, 0, sizeof(rb_node_pool_bitmap)); + + // Initialize runqueue + EEVDFRunqueue* rq = &eevdf_scheduler.rq; + rq->rb_root = NULL; + rq->rb_leftmost = NULL; + rq->min_vruntime = 0; + rq->load_weight = 0; + rq->nr_running = 0; + rq->current_slot = 0; + + eevdf_scheduler.tick_counter = 1; + eevdf_scheduler.total_processes = 0; + eevdf_scheduler.context_switch_overhead = 5; + + // Initialize idle process + EEVDFProcessControlBlock* idle_proc = &processes[0]; + FormatA(idle_proc->name, sizeof(idle_proc->name), "Idle"); + idle_proc->pid = 0; + idle_proc->state = PROC_RUNNING; + idle_proc->privilege_level = EEVDF_PROC_PRIV_SYSTEM; + idle_proc->creation_time = EEVDFGetSystemTicks(); + EEVDFSetTaskNice(idle_proc, 0); + idle_proc->vruntime = 0; + idle_proc->exec_start = GetNS(); + + // Initialize idle process security token + EEVDFSecurityToken* token = &idle_proc->token; + token->magic = EEVDF_SECURITY_MAGIC; + token->creator_pid = 0; + token->privilege = EEVDF_PROC_PRIV_SYSTEM; + token->flags = EEVDF_PROC_FLAG_CORE; + token->creation_tick = idle_proc->creation_time; + token->checksum = 0; + token->checksum = EEVDFCalculateSecureChecksum(token, 0); + + FormatA(idle_proc->ProcessRuntimePath, sizeof(idle_proc->ProcessRuntimePath), "%s/%d", RuntimeServices, idle_proc->pid); + + process_count = 1; + active_process_bitmap |= 1ULL; + + return 0; +} + +uint32_t EEVDFCreateProcess(const char* name, void (*entry_point)(void)) { + if (UNLIKELY(!entry_point)) { + PANIC("EEVDFCreateProcess: NULL entry point"); + } + + irq_flags_t flags = SpinLockIrqSave(&scheduler_lock); + + if (UNLIKELY(process_count >= EEVDF_MAX_PROCESSES)) { + SpinUnlockIrqRestore(&scheduler_lock, flags); + PANIC("EEVDFCreateProcess: Too many processes"); + } + + // Find free slot + int slot = FindFreeSlotFast(); + if (UNLIKELY(slot == -1)) { + SpinUnlockIrqRestore(&scheduler_lock, flags); + PANIC("EEVDFCreateProcess: No free process slots"); + } + + // Allocate PID + uint32_t new_pid = 0; + SpinLock(&pid_lock); + for (int i = 1; i < EEVDF_MAX_PROCESSES; i++) { + int idx = i / 64; + int bit = i % 64; + if (!(pid_bitmap[idx] & (1ULL << bit))) { + pid_bitmap[idx] |= (1ULL << bit); + new_pid = i; + break; + } + } + SpinUnlock(&pid_lock); + + if (new_pid == 0) { + FreeSlotFast(slot); + SpinUnlockIrqRestore(&scheduler_lock, flags); + PANIC("EEVDFCreateProcess: PID exhaustion"); + } + + // Clear process structure + FastMemset(&processes[slot], 0, sizeof(EEVDFProcessControlBlock)); + + // Allocate stack + void* stack = VMemAllocStack(EEVDF_STACK_SIZE); + if (UNLIKELY(!stack)) { + FreeSlotFast(slot); + SpinUnlockIrqRestore(&scheduler_lock, flags); + PANIC("EEVDFCreateProcess: Failed to allocate stack"); + } + + // Initialize process + EEVDFProcessControlBlock* proc = &processes[slot]; + FormatA(proc->name, sizeof(proc->name), "%s", name ? name : FormatS("proc%d", slot)); + proc->pid = new_pid; + proc->state = PROC_READY; + proc->stack = stack; + proc->privilege_level = EEVDF_PROC_PRIV_NORM; + proc->creation_time = EEVDFGetSystemTicks(); + EEVDFSetTaskNice(proc, EEVDF_DEFAULT_NICE); + + // Set virtual time to current minimum to ensure fairness + proc->vruntime = eevdf_scheduler.rq.min_vruntime; + proc->exec_start = GetNS(); + + // Initialize security token + EEVDFSecurityToken* token = &proc->token; + token->magic = EEVDF_SECURITY_MAGIC; + token->creator_pid = 0; // TODO: get current process PID + token->privilege = EEVDF_PROC_PRIV_NORM; + token->flags = EEVDF_PROC_FLAG_NONE; + token->creation_tick = proc->creation_time; + token->checksum = EEVDFCalculateSecureChecksum(token, new_pid); + + // Set up context + uint64_t rsp = (uint64_t)stack + EEVDF_STACK_SIZE; + rsp &= ~0xF; // 16-byte alignment + + // Push exit stub as return address + rsp -= 8; + *(uint64_t*)rsp = (uint64_t)ProcessExitStubEEVDF; + + proc->context.rsp = rsp; + proc->context.rip = (uint64_t)entry_point; + proc->context.rflags = 0x202; + proc->context.cs = 0x08; + proc->context.ss = 0x10; + + // Initialize IPC queue + proc->ipc_queue.head = 0; + proc->ipc_queue.tail = 0; + proc->ipc_queue.count = 0; + + FormatA(proc->ProcessRuntimePath, sizeof(proc->ProcessRuntimePath), "%s/%d", RuntimeProcesses, new_pid); + + // Update counters + __sync_fetch_and_add(&process_count, 1); + ready_process_bitmap |= (1ULL << slot); + eevdf_scheduler.total_processes++; + + // Add to scheduler + EEVDFEnqueueTask(&eevdf_scheduler.rq, proc); + + SpinUnlockIrqRestore(&scheduler_lock, flags); + return new_pid; +} + +EEVDFProcessControlBlock* EEVDFGetCurrentProcess(void) { + if (current_process >= EEVDF_MAX_PROCESSES) { + PANIC("EEVDFGetCurrentProcess: Invalid current process index"); + } + return &processes[current_process]; +} + +EEVDFProcessControlBlock* EEVDFGetCurrentProcessByPID(uint32_t pid) { + ReadLock(&process_table_rwlock_eevdf, pid); + for (int i = 0; i < EEVDF_MAX_PROCESSES; i++) { + if (processes[i].pid == pid && processes[i].state != PROC_TERMINATED) { + EEVDFProcessControlBlock* found = &processes[i]; + ReadUnlock(&process_table_rwlock_eevdf, pid); + return found; + } + } + ReadUnlock(&process_table_rwlock_eevdf, pid); + return NULL; +} + +void EEVDFYield(void) { + // Simple yield - just request a schedule + need_schedule = 1; + volatile int delay = eevdf_scheduler.total_processes * 100; + while (delay-- > 0) __asm__ __volatile__("pause"); +} + +void EEVDFKillProcess(uint32_t pid) { + // TODO: Implement process termination (similar to MLFQ) + PrintKernel("EEVDF: Kill process not fully implemented yet\n"); +} + +void EEVDFKillCurrentProcess(const char* reason) { + // TODO: Implement current process termination + PrintKernel("EEVDF: Kill current process not fully implemented yet: "); + PrintKernel(reason); + PrintKernel("\n"); +} + +void EEVDFProcessBlocked(uint32_t slot) { + if (slot >= EEVDF_MAX_PROCESSES) return; + + EEVDFProcessControlBlock* proc = &processes[slot]; + proc->io_operations++; + + if (slot == eevdf_scheduler.rq.current_slot) { + need_schedule = 1; + } +} + +void EEVDFWakeupTask(EEVDFProcessControlBlock* p) { + if (!p || p->state != PROC_BLOCKED) return; + + p->state = PROC_READY; + p->last_wakeup = GetNS(); + + // Add back to runqueue + EEVDFEnqueueTask(&eevdf_scheduler.rq, p); +} + +void EEVDFCleanupTerminatedProcess(void) { + // TODO: Implement cleanup (similar to MLFQ) +} + +// ============================================================================= +// Statistics and Debugging +// ============================================================================= + +void EEVDFDumpSchedulerState(void) { + PrintKernel("[EEVDF] Current slot: "); + PrintKernelInt(eevdf_scheduler.rq.current_slot); + PrintKernel(" Nr running: "); + PrintKernelInt(eevdf_scheduler.rq.nr_running); + PrintKernel(" Load weight: "); + PrintKernelInt(eevdf_scheduler.rq.load_weight); + PrintKernel("\n[EEVDF] Min vruntime: "); + PrintKernelInt((uint32_t)eevdf_scheduler.rq.min_vruntime); + PrintKernel(" Total processes: "); + PrintKernelInt(eevdf_scheduler.total_processes); + PrintKernel(" Context switches: "); + PrintKernelInt((uint32_t)eevdf_scheduler.switch_count); + PrintKernel("\n"); +} + +void EEVDFListProcesses(void) { + PrintKernel("\n--- EEVDF Process List ---\n"); + PrintKernel("PID\tState \tNice\tWeight\tVRuntime\tCPU Time\tName\n"); + PrintKernel("---------------------------------------------------------------\n"); + + for (int i = 0; i < EEVDF_MAX_PROCESSES; i++) { + if (i == 0 || processes[i].pid != 0) { + const EEVDFProcessControlBlock* p = &processes[i]; + + PrintKernelInt(p->pid); + PrintKernel("\t"); + switch (p->state) { + case PROC_TERMINATED: PrintKernel("TERMINATED"); break; + case PROC_READY: PrintKernel("READY "); break; + case PROC_RUNNING: PrintKernel("RUNNING "); break; + case PROC_BLOCKED: PrintKernel("BLOCKED "); break; + case PROC_ZOMBIE: PrintKernel("ZOMBIE "); break; + case PROC_DYING: PrintKernel("DYING "); break; + default: PrintKernel("UNKNOWN "); break; + } + PrintKernel("\t"); + PrintKernelInt(p->nice); + PrintKernel("\t"); + PrintKernelInt(p->weight); + PrintKernel("\t"); + PrintKernelInt((uint32_t)p->vruntime); + PrintKernel("\t"); + PrintKernelInt((uint32_t)p->cpu_time_accumulated); + PrintKernel("\t"); + PrintKernel(p->name); + PrintKernel("\n"); + } + } + PrintKernel("---------------------------------------------------------------\n"); +} + +void EEVDFGetProcessStats(uint32_t pid, uint32_t* cpu_time, uint32_t* wait_time, uint32_t* preemptions) { + ReadLock(&process_table_rwlock_eevdf, pid); + EEVDFProcessControlBlock* proc = EEVDFGetCurrentProcessByPID(pid); + if (!proc) { + if (cpu_time) *cpu_time = 0; + if (wait_time) *wait_time = 0; + if (preemptions) *preemptions = 0; + ReadUnlock(&process_table_rwlock_eevdf, pid); + return; + } + + if (cpu_time) *cpu_time = (uint32_t)proc->cpu_time_accumulated; + if (wait_time) *wait_time = (uint32_t)proc->wait_sum; + if (preemptions) *preemptions = proc->preemption_count; + ReadUnlock(&process_table_rwlock_eevdf, pid); +} + +void EEVDFDumpPerformanceStats(void) { + PrintKernel("[EEVDF-PERF] Context switches: "); + PrintKernelInt((uint32_t)context_switches); + PrintKernel("\n[EEVDF-PERF] Scheduler calls: "); + PrintKernelInt((uint32_t)scheduler_calls); + PrintKernel("\n[EEVDF-PERF] Active processes: "); + PrintKernelInt(__builtin_popcountll(active_process_bitmap)); + PrintKernel("\n[EEVDF-PERF] Switch count: "); + PrintKernelInt((uint32_t)eevdf_scheduler.switch_count); + PrintKernel("\n[EEVDF-PERF] Migration count: "); + PrintKernelInt((uint32_t)eevdf_scheduler.migration_count); + PrintKernel("\n"); +} + +// Preemption check +int EEVDFCheckPreempt(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p) { + EEVDFProcessControlBlock* curr = &processes[rq->current_slot]; + + // Always preempt if no current task or idle task + if (rq->current_slot == 0 || !curr) return 1; + + // Check if new task has earlier deadline (simplified EEVDF) + if (p->deadline < curr->deadline) return 1; + + // Check if new task has significantly lower vruntime + if (p->vruntime + EEVDF_WAKEUP_GRANULARITY < curr->vruntime) return 1; + + return 0; +} + +void EEVDFYieldTask(EEVDFRunqueue* rq) { + if (rq->current_slot == 0) return; + + EEVDFProcessControlBlock* curr = &processes[rq->current_slot]; + + // Update current task and yield + EEVDFUpdateCurr(rq, curr); + curr->state = PROC_READY; + + // Re-enqueue with updated vruntime + EEVDFEnqueueTask(rq, curr); + + need_schedule = 1; +} \ No newline at end of file diff --git a/kernel/sched/EEVDF.h b/kernel/sched/EEVDF.h new file mode 100644 index 0000000..4839d3f --- /dev/null +++ b/kernel/sched/EEVDF.h @@ -0,0 +1,224 @@ +#ifndef VF_EEVDF_SCHED_H +#define VF_EEVDF_SCHED_H + +#include "Ipc.h" +#include "Shared.h" +#include "stdint.h" +#include "x64.h" + +// ============================================================================= +// EEVDF Parameters - Earliest Eligible Virtual Deadline First +// ============================================================================= + +// Core Scheduler Configuration +#define EEVDF_MAX_PROCESSES 64 // Same as MLFQ for consistency +#define EEVDF_MIN_GRANULARITY 750000 // 0.75ms minimum time slice in ns +#define EEVDF_TARGET_LATENCY 6000000 // 6ms target latency in ns +#define EEVDF_WAKEUP_GRANULARITY 1000000 // 1ms wakeup granularity in ns + +// Nice level constants +#define EEVDF_NICE_WIDTH 4 // Nice level width (log2) +#define EEVDF_NICE_0_LOAD 1024 // Load weight for nice 0 +#define EEVDF_MIN_NICE (-20) +#define EEVDF_MAX_NICE 19 +#define EEVDF_DEFAULT_NICE 0 + +// Virtual time constants +#define EEVDF_TIME_SLICE_NS (4 * 1000000) // 4ms default time slice +#define EEVDF_MAX_TIME_SLICE_NS (100 * 1000000) // 100ms max time slice +#define EEVDF_MIN_TIME_SLICE_NS (100000) // 0.1ms min time slice + +// Load balancing and migration +#define EEVDF_MIGRATION_COST_NS 500000 // 0.5ms migration cost +#define EEVDF_LOAD_BALANCE_INTERVAL 5000000 // 5ms between load balance attempts + +// Preemption control +#define EEVDF_PREEMPT_THRESHOLD_NS 1000000 // 1ms preemption threshold +#define EEVDF_YIELD_GRANULARITY_NS 100000 // 0.1ms yield granularity + +// Security and Process Management (same as MLFQ) +#define EEVDF_TERMINATION_QUEUE_SIZE EEVDF_MAX_PROCESSES +#define EEVDF_CLEANUP_MAX_PER_CALL 3 +#define EEVDF_SECURITY_VIOLATION_LIMIT 3 +#define EEVDF_STACK_SIZE 4096 +#define EEVDF_CACHE_LINE_SIZE 64 + +// Process privilege levels (same as MLFQ) +#define EEVDF_PROC_PRIV_SYSTEM 0 +#define EEVDF_PROC_PRIV_NORM 1 +#define EEVDF_PROC_PRIV_RESTRICTED 2 + +// Security flags (same as MLFQ) +#define EEVDF_PROC_FLAG_NONE 0U +#define EEVDF_PROC_FLAG_IMMUNE (1U << 0) +#define EEVDF_PROC_FLAG_CRITICAL (1U << 1) +#define EEVDF_PROC_FLAG_SUPERVISOR (1U << 3) +#define EEVDF_PROC_FLAG_CORE (EEVDF_PROC_FLAG_IMMUNE | EEVDF_PROC_FLAG_SUPERVISOR | EEVDF_PROC_FLAG_CRITICAL) + +// Nice-to-weight conversion table (based on Linux CFS) +extern const uint32_t eevdf_nice_to_weight[40]; +extern const uint32_t eevdf_nice_to_wmult[40]; + +// EEVDF-specific structures +typedef struct { + uint64_t magic; + uint32_t creator_pid; + uint8_t privilege; + uint8_t flags; + uint64_t creation_tick; + uint64_t checksum; +} __attribute__((packed)) EEVDFSecurityToken; + +// Use the same structure for context switching to avoid mismatches +typedef Registers EEVDFProcessContext; + +// Red-black tree node for the EEVDF runqueue +typedef struct EEVDFRBNode { + struct EEVDFRBNode* left; + struct EEVDFRBNode* right; + struct EEVDFRBNode* parent; + uint8_t color; // 0 = black, 1 = red + uint32_t slot; // Index into process array +} EEVDFRBNode; + +// EEVDF Process Control Block +typedef struct { + char name[64]; + uint32_t pid; + ProcessState state; + void* stack; + + // Scheduling fields + int8_t nice; // Nice level (-20 to +19) + uint32_t weight; // Scheduling weight (from nice level) + uint32_t inv_weight; // Inverse weight for calculations + + // Virtual time tracking + uint64_t vruntime; // Virtual runtime (key for ordering) + uint64_t deadline; // Virtual deadline + uint64_t slice_ns; // Current time slice length + uint64_t exec_start; // When this task started executing + uint64_t sum_exec_runtime; // Total execution time + + // Statistics + uint64_t wait_start; // When task started waiting + uint64_t wait_sum; // Total wait time + uint64_t sleep_start; // When task started sleeping + uint64_t sleep_sum; // Total sleep time + uint64_t last_wakeup; // Last wakeup time + + // Tree management + EEVDFRBNode* rb_node; // Red-black tree node + + // Security and system fields (same as MLFQ) + uint8_t privilege_level; + uint32_t io_operations; + uint32_t preemption_count; + uint64_t cpu_time_accumulated; + uint64_t creation_time; + uint32_t parent_pid; + TerminationReason term_reason; + uint32_t exit_code; + uint64_t termination_time; + + EEVDFSecurityToken token; + MessageQueue ipc_queue; + EEVDFProcessContext context; + char ProcessRuntimePath[256]; +} EEVDFProcessControlBlock; + +// EEVDF Runqueue (per-CPU, but we have single CPU) +typedef struct { + // Red-black tree root for runnable tasks + EEVDFRBNode* rb_root; + EEVDFRBNode* rb_leftmost; // Leftmost node (minimum vruntime) + + // Virtual time tracking + uint64_t min_vruntime; // Minimum virtual runtime + uint64_t clock; // Runqueue clock + uint64_t clock_task; // Per-task clock + + // Load tracking + uint32_t load_weight; // Total weight of runnable tasks + uint32_t nr_running; // Number of runnable tasks + + // Current running task + uint32_t current_slot; // Currently running task slot + + // Statistics + uint64_t exec_clock; // Execution clock + uint64_t avg_idle; // Average idle time + uint64_t avg_vruntime; // Average vruntime +} EEVDFRunqueue; + +// Main EEVDF scheduler structure +typedef struct { + EEVDFRunqueue rq; // Main runqueue + uint32_t total_processes; // Total active processes + uint64_t tick_counter; // Global tick counter + uint32_t context_switch_overhead; // Measured context switch overhead + + // Load balancing (future multi-CPU support) + uint64_t next_balance; // Next load balance time + uint64_t load_balance_interval; // Load balance interval + + // Preemption control + uint64_t last_preempt_check; // Last preemption check time + uint32_t preempt_count; // Number of preemptions + + // Performance counters + uint64_t schedule_count; // Number of schedule() calls + uint64_t switch_count; // Number of context switches + uint64_t migration_count; // Number of task migrations +} EEVDFScheduler; + +// Function declarations + +// Core scheduler functions +int EEVDFSchedInit(void); +uint32_t EEVDFCreateProcess(const char* name, void (*entry_point)(void)); +EEVDFProcessControlBlock* EEVDFGetCurrentProcess(void); +EEVDFProcessControlBlock* EEVDFGetCurrentProcessByPID(uint32_t pid); +void EEVDFYield(void); +void EEVDFSchedule(Registers* regs); +void EEVDFKillProcess(uint32_t pid); +void EEVDFKillCurrentProcess(const char* reason); + +// Time management +uint64_t EEVDFGetSystemTicks(void); +uint64_t EEVDFGetNanoseconds(void); +void EEVDFUpdateClock(EEVDFRunqueue* rq); + +// Virtual time functions +uint64_t EEVDFCalcDelta(uint64_t delta_exec, uint32_t weight, uint32_t lw); +void EEVDFUpdateCurr(EEVDFRunqueue* rq, EEVDFProcessControlBlock* curr); +uint64_t EEVDFCalcSlice(EEVDFRunqueue* rq, EEVDFProcessControlBlock* se); + +// Tree management +void EEVDFEnqueueTask(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p); +void EEVDFDequeueTask(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p); +EEVDFProcessControlBlock* EEVDFPickNext(EEVDFRunqueue* rq); + +// Preemption and yielding +int EEVDFCheckPreempt(EEVDFRunqueue* rq, EEVDFProcessControlBlock* p); +void EEVDFYieldTask(EEVDFRunqueue* rq); + +// Wakeup handling +void EEVDFWakeupTask(EEVDFProcessControlBlock* p); +void EEVDFProcessBlocked(uint32_t slot); + +// Process management +void EEVDFCleanupTerminatedProcess(void); + +// Statistics and debugging +void EEVDFDumpSchedulerState(void); +void EEVDFListProcesses(void); +void EEVDFGetProcessStats(uint32_t pid, uint32_t* cpu_time, uint32_t* wait_time, uint32_t* preemptions); +void EEVDFDumpPerformanceStats(void); + +// Nice level functions +void EEVDFSetTaskNice(EEVDFProcessControlBlock* p, int nice); +uint32_t EEVDFNiceToWeight(int nice); +uint32_t EEVDFNiceToWmult(int nice); + +#endif // VF_EEVDF_SCHED_H \ No newline at end of file diff --git a/kernel/sched/MLFQ.c b/kernel/sched/MLFQ.c index bdfd571..5cf2f27 100644 --- a/kernel/sched/MLFQ.c +++ b/kernel/sched/MLFQ.c @@ -51,7 +51,7 @@ static volatile uint32_t current_process = 0; static volatile uint32_t process_count = 0; static volatile int need_schedule = 0; static volatile int scheduler_lock = 0; -rwlock_t process_table_rwlock = {0}; +rwlock_t process_table_rwlock_mlfq = {0}; // Security subsystem uint32_t security_manager_pid = 0; @@ -1239,15 +1239,15 @@ MLFQProcessControlBlock* MLFQGetCurrentProcess(void) { MLFQProcessControlBlock* MLFQGetCurrentProcessByPID(uint32_t pid) { MLFQProcessControlBlock* current = MLFQGetCurrentProcess(); - ReadLock(&process_table_rwlock, current->pid); + ReadLock(&process_table_rwlock_mlfq, current->pid); for (int i = 0; i < MAX_PROCESSES; i++) { if (processes[i].pid == pid && processes[i].state != PROC_TERMINATED) { MLFQProcessControlBlock* found = &processes[i]; - ReadUnlock(&process_table_rwlock, current->pid); + ReadUnlock(&process_table_rwlock_mlfq, current->pid); return found; } } - ReadUnlock(&process_table_rwlock, current->pid); + ReadUnlock(&process_table_rwlock_mlfq, current->pid); return NULL; } @@ -1950,7 +1950,7 @@ void MLFQKillCurrentProcess(const char * reason) { // Get detailed process scheduling information void MLFQGetProcessStats(uint32_t pid, uint32_t* cpu_time, uint32_t* io_ops, uint32_t* preemptions) { - ReadLock(&process_table_rwlock, pid); + ReadLock(&process_table_rwlock_mlfq, pid); MLFQProcessControlBlock* proc = MLFQGetCurrentProcessByPID(pid); if (!proc) { if (cpu_time) *cpu_time = 0; @@ -1962,5 +1962,5 @@ void MLFQGetProcessStats(uint32_t pid, uint32_t* cpu_time, uint32_t* io_ops, uin if (cpu_time) *cpu_time = (uint32_t)proc->cpu_time_accumulated; if (io_ops) *io_ops = proc->io_operations; if (preemptions) *preemptions = proc->preemption_count; - ReadUnlock(&process_table_rwlock, pid); + ReadUnlock(&process_table_rwlock_mlfq, pid); } diff --git a/meson.build b/meson.build index 2a6c46c..9acb6b7 100644 --- a/meson.build +++ b/meson.build @@ -113,6 +113,7 @@ vf_config_base = [ '-DVF_CONFIG_USE_CERBERUS', '-DVF_CONFIG_CERBERUS_STACK_PROTECTION', '-DVF_CONFIG_SCHED_MLFQ', +# '-DVF_CONFIG_SCHED_EEVDF', ] vf_config_optional = [ @@ -162,6 +163,7 @@ kernel_core_sources = files([ # Scheduler sources sched_sources = files([ 'kernel/sched/MLFQ.c', + 'kernel/sched/EEVDF.c', ]) # Kernel utilities diff --git a/scripts/mangle.py b/scripts/mangle.py index b9ddfee..362b48c 100644 --- a/scripts/mangle.py +++ b/scripts/mangle.py @@ -20,9 +20,7 @@ def __init__(self): '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() diff --git a/xmake.lua b/xmake.lua index aa12de5..e75eb50 100644 --- a/xmake.lua +++ b/xmake.lua @@ -8,7 +8,7 @@ set_version("0.0.2-development3") set_languages("c11", "cxx17") -- Force clang toolchain -set_toolchains("clang") +set_toolchains("clang", "nasm") -- ============================================================================ -- Target: voidframe kernel @@ -45,6 +45,7 @@ target("voidframe") -- Scheduler sources "kernel/sched/MLFQ.c", + "kernel/sched/EEVDF.c", -- Kernel utilities "kernel/etc/Shell.c", @@ -237,6 +238,7 @@ target("voidframe") "VF_CONFIG_USE_CERBERUS", "VF_CONFIG_CERBERUS_STACK_PROTECTION", "VF_CONFIG_SCHED_MLFQ" +-- "VF_CONFIG_SCHED_EEVDF" ) add_asdefines(