diff --git a/Kernel/Core/stdint.h b/Kernel/Core/stdint.h index 87de4b6..f7997e0 100644 --- a/Kernel/Core/stdint.h +++ b/Kernel/Core/stdint.h @@ -6,6 +6,8 @@ #define VOIDFRAME_STDINT_H #define NULL ((void*)0) +#define INT32_MAX ((int32_t)0x7FFFFFFF) +#define INT32_MIN ((int32_t)0x80000000) typedef unsigned char uint8_t; _Static_assert(sizeof(uint8_t) == 1, "sizeof(uint8_t) != 1"); @@ -19,4 +21,16 @@ _Static_assert(sizeof(uint32_t) == 4, "sizeof(uint32_t) != 4"); typedef unsigned long long uint64_t; _Static_assert(sizeof(uint64_t) == 8, "sizeof(uint64_t) != 8"); +typedef unsigned char int8_t; +_Static_assert(sizeof(int8_t) == 1, "sizeof(int8_t) != 1"); + +typedef unsigned short int16_t; +_Static_assert(sizeof(int16_t) == 2, "sizeof(int16_t) != 2"); + +typedef unsigned int int32_t; +_Static_assert(sizeof(int32_t) == 4, "sizeof(int32_t) != 4"); + +typedef unsigned long long int64_t; +_Static_assert(sizeof(int64_t) == 8, "sizeof(int64_t) != 8"); + #endif diff --git a/Kernel/Drivers/Interrupts.c b/Kernel/Drivers/Interrupts.c index b859759..4b1055b 100644 --- a/Kernel/Drivers/Interrupts.c +++ b/Kernel/Drivers/Interrupts.c @@ -71,9 +71,9 @@ void InterruptHandler(struct Registers* regs) { ASSERT(regs != NULL); if (regs->interrupt_number == 32) { tick_count++; - // FastDisplayTicks(tick_count); // Re-enabled + // FastDisplayTicks(tick_count); + ScheduleFromInterrupt(regs); // Re-enabledc outb(0x20, 0x20); - ScheduleFromInterrupt(regs); // Re-enabled return; } if (regs->interrupt_number == 13) { diff --git a/Kernel/Process/Process.c b/Kernel/Process/Process.c index de94ebc..0e07a32 100644 --- a/Kernel/Process/Process.c +++ b/Kernel/Process/Process.c @@ -20,7 +20,233 @@ extern void SwitchContext(ProcessContext * old, ProcessContext * new); static uint32_t last_scheduled_slot = 0; // For round-robin optimization static uint32_t active_process_bitmap = 0; // Bitmap for fast slot tracking (up to 32 processes) +static Scheduler MLFQscheduler; // Fast slot allocation using bitmap +void DumpSchedulerState(void) { + PrintKernel("[SCHED] Current: "); + PrintKernelInt(MLFQscheduler.current_running); + PrintKernel(" Quantum: "); + PrintKernelInt(MLFQscheduler.quantum_remaining); + PrintKernel(" Bitmap: "); + PrintKernelInt(MLFQscheduler.active_bitmap); + PrintKernel("\n"); + + for (int i = 0; i < MAX_PRIORITY_LEVELS; i++) { + if (MLFQscheduler.queues[i].count > 0) { + PrintKernel(" Priority "); + PrintKernelInt(i); + PrintKernel(": "); + PrintKernelInt(MLFQscheduler.queues[i].count); + PrintKernel(" processes, quantum: "); + PrintKernelInt(MLFQscheduler.queues[i].quantum); + PrintKernel("\n"); + } + } +} + +static inline void EnQueue(PriorityQueue* q, uint32_t slot) { + if (q->count >= MAX_PROCESSES) return; + q->process_slots[q->tail] = slot; + q->tail = (q->tail + 1) % MAX_PROCESSES; + q->count++; +} + +static inline uint32_t DeQueue(PriorityQueue* q) { + if (q->count == 0) return MAX_PROCESSES; + uint32_t slot = q->process_slots[q->head]; + q->head = (q->head + 1) % MAX_PROCESSES; + q->count--; + return slot; +} + +static inline int QueueEmpty(PriorityQueue* q) { + return q->count == 0; +} + +void InitScheduler(void) { + FastMemset(&MLFQscheduler, 0, sizeof(Scheduler)); + + // Initialize priority queues with different time quantums + for (int i = 0; i < MAX_PRIORITY_LEVELS; i++) { + MLFQscheduler.queues[i].quantum = QUANTUM_BASE * (1 << i); // 10, 20, 40, 80 ticks + MLFQscheduler.queues[i].head = 0; + MLFQscheduler.queues[i].tail = 0; + MLFQscheduler.queues[i].count = 0; + } + + MLFQscheduler.current_running = 0; // Start with idle + MLFQscheduler.quantum_remaining = 0; + MLFQscheduler.active_bitmap = 0; +} + +// Add process to scheduler +void AddToScheduler(uint32_t slot) { + if (slot == 0) return; // Don't schedule idle process + + Process* proc = &processes[slot]; + if (proc->state != PROC_READY) return; + + // Determine initial priority based on privilege level + uint32_t priority = 0; + if (proc->privilege_level == PROC_PRIV_SYSTEM) { + priority = 0; // Highest priority for system processes + } else { + priority = 1; // Start user processes at level 1 + } + + // Clamp priority + if (priority >= MAX_PRIORITY_LEVELS) { + priority = MAX_PRIORITY_LEVELS - 1; + } + + proc->priority = priority; + EnQueue(&MLFQscheduler.queues[priority], slot); + MLFQscheduler.active_bitmap |= (1U << priority); +} + +// Remove process from scheduler +void RemoveFromScheduler(uint32_t slot) { + // This is expensive but rarely called + for (int level = 0; level < MAX_PRIORITY_LEVELS; level++) { + PriorityQueue* q = &MLFQscheduler.queues[level]; + for (uint32_t i = 0; i < q->count; i++) { + uint32_t idx = (q->head + i) % MAX_PROCESSES; + if (q->process_slots[idx] == slot) { + // Remove by shifting + for (uint32_t j = i; j < q->count - 1; j++) { + uint32_t curr_idx = (q->head + j) % MAX_PROCESSES; + uint32_t next_idx = (q->head + j + 1) % MAX_PROCESSES; + q->process_slots[curr_idx] = q->process_slots[next_idx]; + } + q->count--; + if (q->tail == 0) q->tail = MAX_PROCESSES - 1; + else q->tail--; + + if (q->count == 0) { + MLFQscheduler.active_bitmap &= ~(1U << level); + } + return; + } + } + } +} +static inline int FindHighestPriorityQueue(void) { + if (MLFQscheduler.active_bitmap == 0) return -1; + + // Find first set bit (lowest index = highest priority) + for (int i = 0; i < MAX_PRIORITY_LEVELS; i++) { + if (MLFQscheduler.active_bitmap & (1U << i)) { + return i; + } + } + return -1; +} + +// Boost all processes to prevent starvation +static void BoostAllProcesses(void) { + // Move all processes to highest priority queue + for (int level = 1; level < MAX_PRIORITY_LEVELS; level++) { + PriorityQueue* src = &MLFQscheduler.queues[level]; + PriorityQueue* dst = &MLFQscheduler.queues[0]; + + while (!QueueEmpty(src)) { + uint32_t slot = DeQueue(src); + processes[slot].priority = 0; + EnQueue(dst, slot); + } + MLFQscheduler.active_bitmap &= ~(1U << level); + } + + if (MLFQscheduler.queues[0].count > 0) { + MLFQscheduler.active_bitmap |= 1U; + } +} + +// Main scheduler - called from timer interrupt +void FastSchedule(struct Registers* regs) { + MLFQscheduler.tick_counter++; + + // Boost all processes periodically to prevent starvation + if (MLFQscheduler.tick_counter - MLFQscheduler.last_boost_tick >= BOOST_INTERVAL) { + BoostAllProcesses(); + MLFQscheduler.last_boost_tick = MLFQscheduler.tick_counter; + } + + Process* current = &processes[MLFQscheduler.current_running]; + + // Handle current process + if (MLFQscheduler.current_running != 0) { // Not idle + // Save context + FastMemcpy(¤t->context, regs, sizeof(struct Registers)); + + // Update process state + if (current->state == PROC_RUNNING) { + current->state = PROC_READY; + + // Check if quantum expired + if (MLFQscheduler.quantum_remaining > 0) { + MLFQscheduler.quantum_remaining--; + + // If quantum not expired and no higher priority processes, keep running + int highest_priority = FindHighestPriorityQueue(); + if (MLFQscheduler.quantum_remaining > 0 && + (highest_priority == -1 || highest_priority >= (int)current->priority)) { + current->state = PROC_RUNNING; + return; // Keep current process running + } + } + + // Quantum expired or higher priority process available + // Demote to lower priority (unless already at lowest) + if (current->priority < MAX_PRIORITY_LEVELS - 1) { + current->priority++; + } + + // Add back to appropriate queue + AddToScheduler(MLFQscheduler.current_running); + } + } + + // Find next process to run + int next_priority = FindHighestPriorityQueue(); + if (next_priority == -1) { + // No processes ready, run idle + MLFQscheduler.current_running = 0; + MLFQscheduler.quantum_remaining = 0; + } else { + // Get next process from highest priority queue + uint32_t next_slot = DeQueue(&MLFQscheduler.queues[next_priority]); + if (MLFQscheduler.queues[next_priority].count == 0) { + MLFQscheduler.active_bitmap &= ~(1U << next_priority); + } + + MLFQscheduler.current_running = next_slot; + MLFQscheduler.quantum_remaining = MLFQscheduler.queues[next_priority].quantum; + } + + // Switch to new process + processes[MLFQscheduler.current_running].state = PROC_RUNNING; + FastMemcpy(regs, &processes[MLFQscheduler.current_running].context, sizeof(struct Registers)); +} + +// Called when process blocks (I/O, IPC, etc.) +void ProcessBlocked(uint32_t slot) { + if (slot == MLFQscheduler.current_running) { + // Current process blocked, trigger immediate reschedule + MLFQscheduler.quantum_remaining = 0; + RequestSchedule(); + } + + // When process unblocks, it goes to higher priority (I/O bound processes get priority) + Process* proc = &processes[slot]; + if (proc->state == PROC_READY && proc->priority > 0) { + proc->priority--; // Boost priority + } +} + +// Simple interface for your existing code + + static int FindFreeSlot(void) { // Skip slot 0 (idle process) for (int i = 1; i < MAX_PROCESSES && i < 32; i++) { @@ -70,6 +296,10 @@ void RequestSchedule(void) { } void Yield() { + Process* current = GetCurrentProcess(); + if (current) { + current->state = PROC_BLOCKED; // Mark as blocked for scheduler to boost + } RequestSchedule(); __asm__ __volatile__("hlt"); } @@ -98,21 +328,14 @@ static void init_token(SecurityToken* token, uint32_t creator_pid, uint8_t privi void ProcessInit(void) { FastMemset(processes, 0, sizeof(Process) * MAX_PROCESSES); - active_process_bitmap = 0; - last_scheduled_slot = 0; - // Create idle process (PID 0) + // Initialize idle process processes[0].pid = 0; processes[0].state = PROC_RUNNING; - processes[0].priority = 255; processes[0].privilege_level = PROC_PRIV_SYSTEM; - processes[0].is_user_mode = 0; - - // Don't set bit 0 in bitmap - idle process is special - init_token(&processes[0].token, 0, PROC_PRIV_SYSTEM, 0); + InitScheduler(); // Initialize new scheduler process_count = 1; - current_process = 0; } uint32_t CreateProcess(void (*entry_point)(void)) { @@ -175,6 +398,9 @@ uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege) { processes[slot].privilege_level = privilege; processes[slot].priority = (privilege == PROC_PRIV_SYSTEM) ? 10 : 100; processes[slot].is_user_mode = (privilege != PROC_PRIV_SYSTEM); + processes[slot].weight = (privilege == PROC_PRIV_SYSTEM) ? 100 : 50; + processes[slot].cpu_time_accumulated = 0; + processes[slot].dynamic_priority_score = 0; // Initialize IPC queue processes[slot].ipc_queue.head = 0; @@ -198,52 +424,12 @@ uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege) { processes[slot].context.ss = 0x10; process_count++; + AddToScheduler(slot); return new_pid; } void ScheduleFromInterrupt(struct Registers* regs) { - ASSERT(regs != NULL); - if (process_count <= 1) return; - - // Save current context - FastMemcpy(&processes[current_process].context, regs, sizeof(struct Registers)); - if (processes[current_process].state == PROC_RUNNING) { - processes[current_process].state = PROC_READY; - } - - // Fast round-robin using bitmap - uint32_t next_slot = current_process; - uint32_t start_slot = (last_scheduled_slot + 1) % MAX_PROCESSES; - - // Look for next ready process starting from where we left off - for (uint32_t i = 0; i < MAX_PROCESSES; i++) { - uint32_t candidate = (start_slot + i) % MAX_PROCESSES; - - // Skip slot 0 unless it's our only option - if (candidate == 0 && process_count > 1) continue; - - // Check if slot is active and process is ready - if (candidate < 32 && (active_process_bitmap & (1U << candidate))) { - if (processes[candidate].state == PROC_READY && processes[candidate].pid != 0) { - next_slot = candidate; - last_scheduled_slot = candidate; - break; - } - } - } - - // Fallback to current process if it's still ready - if (next_slot == current_process && processes[current_process].state != PROC_READY) { - next_slot = 0; // Idle process - last_scheduled_slot = 0; - } - - // Switch process - current_process = next_slot; - processes[current_process].state = PROC_RUNNING; - - // Restore context - FastMemcpy(regs, &processes[current_process].context, sizeof(struct Registers)); + FastSchedule(regs); } @@ -286,8 +472,8 @@ void SystemService(void) { } } void SecureKernelIntegritySubsystem(void) { + PrintKernel("[SYSTEM] MLFQ scheduler initializing...\n"); PrintKernel("[SYSTEM] SecureKernelIntegritySubsystem() initializing...\n"); - Process* current = GetCurrentProcess(); RegisterSecurityManager(current->pid); diff --git a/Kernel/Process/Process.h b/Kernel/Process/Process.h index 3375344..81bacb2 100644 --- a/Kernel/Process/Process.h +++ b/Kernel/Process/Process.h @@ -20,10 +20,10 @@ typedef struct { } __attribute__((packed)) SecurityToken; typedef enum { + PROC_TERMINATED = 0, // IMPORTANT: Keep this as 0 since your code expects it PROC_READY, PROC_RUNNING, - PROC_BLOCKED, - PROC_TERMINATED = 0 + PROC_BLOCKED } ProcessState; // DO NOT TOUCH THIS STRUCTURE - must match interrupt ASM stack layout @@ -48,22 +48,61 @@ typedef struct { uint8_t is_user_mode; uint8_t privilege_level; uint8_t _padding; + uint32_t weight; // Base weight for scheduling (legacy - can remove later) + uint64_t cpu_time_accumulated; // Accumulated CPU time + int32_t dynamic_priority_score; // Score for dynamic adjustment (legacy - can remove later) SecurityToken token; MessageQueue ipc_queue; ProcessContext context; } Process; +// New scheduler constants +#define MAX_PRIORITY_LEVELS 4 +#define QUANTUM_BASE 10 // Base time quantum in ticks +#define BOOST_INTERVAL 1000 // Boost all processes every 1000 ticks + +typedef struct { + uint32_t process_slots[MAX_PROCESSES]; + uint32_t head; + uint32_t tail; + uint32_t count; + uint32_t quantum; // Time quantum for this priority level +} PriorityQueue; + +typedef struct { + PriorityQueue queues[MAX_PRIORITY_LEVELS]; + uint32_t current_running; + uint32_t tick_counter; + uint32_t quantum_remaining; + uint32_t last_boost_tick; + uint32_t active_bitmap; // Bitmap of non-empty queues +} Scheduler; + +// Core process functions void ProcessInit(void); uint32_t CreateProcess(void (*entry_point)(void)); uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege); +Process* GetCurrentProcess(void); +Process* GetProcessByPid(uint32_t pid); +void CleanupTerminatedProcesses(void); + +// Legacy scheduler functions (can be removed after migration) void RequestSchedule(); int ShouldSchedule(); -void Schedule(void); void Yield(void); -Process* GetCurrentProcess(void); -Process* GetProcessByPid(uint32_t pid); void ScheduleFromInterrupt(struct Registers* regs); + +// New scheduler functions +void InitScheduler(void); +void AddToScheduler(uint32_t slot); +void RemoveFromScheduler(uint32_t slot); +void FastSchedule(struct Registers* regs); +void ProcessBlocked(uint32_t slot); +void DumpSchedulerState(void); + +// Security functions void RegisterSecurityManager(uint32_t pid); void SecureKernelIntegritySubsystem(void); void SystemService(void); + #endif \ No newline at end of file