Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions Kernel/Core/Kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,7 @@ void KernelMain(uint32_t magic, uint32_t info) {
PrintKernelSuccess("[KERNEL] Core system modules loaded\n");
PrintKernelSuccess("[KERNEL] Kernel initialization complete\n");
PrintKernelSuccess("[SYSTEM] Transferring control to SecureKernelIntegritySubsystem...\n\n");

// Enable interrupts
asm volatile("sti");

while (1) {
if (ShouldSchedule()) {
RequestSchedule();
Expand Down
246 changes: 191 additions & 55 deletions Kernel/Process/Process.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,78 @@ static Scheduler MLFQscheduler;
static SchedulerNode scheduler_node_pool[MAX_PROCESSES];
static uint32_t scheduler_node_pool_bitmap[(MAX_PROCESSES + 31) / 32];

static uint32_t termination_queue[MAX_PROCESSES];
static uint32_t term_queue_head = 0;
static uint32_t term_queue_tail = 0;
static uint32_t term_queue_count = 0;

uint64_t GetSystemTicks(void) {
return MLFQscheduler.tick_counter;
}

static void AddToTerminationQueue(uint32_t slot) {
if (term_queue_count >= MAX_PROCESSES) return;

termination_queue[term_queue_tail] = slot;
term_queue_tail = (term_queue_tail + 1) % MAX_PROCESSES;
term_queue_count++;
}
Comment on lines +36 to +42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential issue: Silent failure when termination queue is full.

The function silently returns when the queue is full, which could lead to zombie processes that never get cleaned up.

Consider logging an error or panic when the queue is full:

 static void AddToTerminationQueue(uint32_t slot) {
-    if (term_queue_count >= MAX_PROCESSES) return;
+    if (term_queue_count >= MAX_PROCESSES) {
+        PrintKernelError("[KERNEL] Termination queue full! Cannot add slot ");
+        PrintKernelInt(slot);
+        PrintKernelError("\n");
+        Panic("Termination queue overflow");
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
static void AddToTerminationQueue(uint32_t slot) {
if (term_queue_count >= MAX_PROCESSES) return;
termination_queue[term_queue_tail] = slot;
term_queue_tail = (term_queue_tail + 1) % MAX_PROCESSES;
term_queue_count++;
}
static void AddToTerminationQueue(uint32_t slot) {
if (term_queue_count >= MAX_PROCESSES) {
PrintKernelError("[KERNEL] Termination queue full! Cannot add slot ");
PrintKernelInt(slot);
PrintKernelError("\n");
Panic("Termination queue overflow");
}
termination_queue[term_queue_tail] = slot;
term_queue_tail = (term_queue_tail + 1) % MAX_PROCESSES;
term_queue_count++;
}
🤖 Prompt for AI Agents
In Kernel/Process/Process.c around lines 36 to 42, the AddToTerminationQueue
function silently returns when the termination queue is full, risking zombie
processes. Modify the function to log an error or trigger a panic when
term_queue_count reaches MAX_PROCESSES, ensuring that this critical condition is
noticed and handled appropriately.


// Remove from termination queue
static uint32_t RemoveFromTerminationQueue(void) {
if (term_queue_count == 0) return MAX_PROCESSES;

uint32_t slot = termination_queue[term_queue_head];
term_queue_head = (term_queue_head + 1) % MAX_PROCESSES;
term_queue_count--;
return slot;
}

void TerminateProcess(uint32_t pid, TerminationReason reason, uint32_t exit_code) {
if (pid == 0) return; // Cannot terminate idle process

Process* proc = GetProcessByPid(pid);
if (!proc || proc->state == PROC_TERMINATED || proc->state == PROC_ZOMBIE) {
return; // Already terminated or doesn't exist
}

// Find the slot
uint32_t slot = proc - processes;
if (slot >= MAX_PROCESSES) return;

PrintKernel("[KERNEL] Terminating process PID: ");
PrintKernelInt(pid);
PrintKernel(" Reason: ");
PrintKernelInt(reason);
PrintKernel("\n");

// Mark as dying to prevent double termination
proc->state = PROC_DYING;
proc->term_reason = reason;
proc->exit_code = exit_code;
proc->termination_time = GetSystemTicks(); // You'll need to implement this

// Remove from scheduler immediately
RemoveFromScheduler(slot);

// If this is the currently running process, we need special handling
if (slot == MLFQscheduler.current_running) {
// Mark for immediate context switch
MLFQscheduler.quantum_remaining = 0;
RequestSchedule();
}

// Add to termination queue for deferred cleanup
AddToTerminationQueue(slot);

// Move to zombie state
proc->state = PROC_ZOMBIE;
}

void KillProcess(uint32_t pid) {
TerminateProcess(pid, TERM_KILLED, 1);
}

void InitSchedulerNodePool(void) {
FastMemset(scheduler_node_pool, 0, sizeof(scheduler_node_pool));
FastMemset(scheduler_node_pool_bitmap, 0, sizeof(scheduler_node_pool_bitmap));
Expand Down Expand Up @@ -280,34 +352,42 @@ void FastSchedule(struct Registers* regs) {

// Handle current process
if (MLFQscheduler.current_running != 0) { // Not idle
// Save context
FastMemcpy(&current->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
// Check if current process is dying or terminated
if (current->state == PROC_DYING || current->state == PROC_ZOMBIE ||
current->state == PROC_TERMINATED) {
// Don't save context, just switch away
MLFQscheduler.current_running = 0; // Switch to idle
MLFQscheduler.quantum_remaining = 0;
} else {
// Save context for healthy processes
FastMemcpy(&current->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++;
}
// 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);
// Add back to appropriate queue
AddToScheduler(MLFQscheduler.current_running);
}
}
}

Expand All @@ -324,13 +404,27 @@ void FastSchedule(struct Registers* regs) {
MLFQscheduler.active_bitmap &= ~(1U << next_priority);
}

MLFQscheduler.current_running = next_slot;
MLFQscheduler.quantum_remaining = MLFQscheduler.queues[next_priority].quantum;
// Verify the process is still valid
if (processes[next_slot].state == PROC_READY) {
MLFQscheduler.current_running = next_slot;
MLFQscheduler.quantum_remaining = MLFQscheduler.queues[next_priority].quantum;
} else {
// Process became invalid, try again
MLFQscheduler.current_running = 0;
MLFQscheduler.quantum_remaining = 0;
}
}


processes[MLFQscheduler.current_running].state = PROC_RUNNING;
FastMemcpy(regs, &processes[MLFQscheduler.current_running].context, sizeof(struct Registers));
// Switch to new process
if (MLFQscheduler.current_running != 0) {
processes[MLFQscheduler.current_running].state = PROC_RUNNING;
current_process = MLFQscheduler.current_running;
FastMemcpy(regs, &processes[MLFQscheduler.current_running].context, sizeof(struct Registers));
} else {
// Running idle - set up idle context
current_process = 0;
// You might want to set up a proper idle context here
}
}

// Called when process blocks (I/O, IPC, etc.)
Expand Down Expand Up @@ -449,14 +543,19 @@ uint32_t CreateProcess(void (*entry_point)(void)) {
}

void ProcessExitStub() {
PrintKernelError("[KERNEL] Process returned from its main function. -FATAL EXECPTION-\n");
PrintKernelWarning("Terminating process PID: ");
PrintKernelInt(GetCurrentProcess()->pid);
PrintKernel("\n");
Process* current = GetCurrentProcess();

GetCurrentProcess()->state = PROC_TERMINATED;
RequestSchedule();
while (1) { __asm__ __volatile__("hlt"); }
PrintKernelWarning("[KERNEL] Process PID ");
PrintKernelInt(current->pid);
PrintKernelWarning(" exited normally\n");

// Use the safe termination function
TerminateProcess(current->pid, TERM_NORMAL, 0);

// Should not reach here, but just in case
while (1) {
__asm__ __volatile__("hlt");
}
}

uint32_t CreateSecureProcess(void (*entry_point)(void), uint8_t privilege) {
Expand Down Expand Up @@ -543,15 +642,48 @@ void ScheduleFromInterrupt(struct Registers* regs) {


void CleanupTerminatedProcesses(void) {
for (int i = 1; i < MAX_PROCESSES; i++) {
if (processes[i].state == PROC_TERMINATED && processes[i].pid != 0) {
if (processes[i].stack) {
FreePage(processes[i].stack);
}
FastMemset(&processes[i], 0, sizeof(Process));
FreeSlot(i);
process_count--;
// Process a limited number per call to avoid long interrupt delays
int cleanup_count = 0;
const int MAX_CLEANUP_PER_CALL = 3;

while (term_queue_count > 0 && cleanup_count < MAX_CLEANUP_PER_CALL) {
uint32_t slot = RemoveFromTerminationQueue();
if (slot >= MAX_PROCESSES) break;

Process* proc = &processes[slot];

// Double-check state
if (proc->state != PROC_ZOMBIE && proc->state != PROC_TERMINATED) {
continue;
}

PrintKernel("[KERNEL] Cleaning up process PID: ");
PrintKernelInt(proc->pid);
PrintKernel("\n");

// Cleanup resources
if (proc->stack) {
FreePage(proc->stack);
proc->stack = NULL;
}

// Clear IPC queue
proc->ipc_queue.head = 0;
proc->ipc_queue.tail = 0;
proc->ipc_queue.count = 0;

// Clear process structure - this will set state to PROC_TERMINATED (0)
uint32_t pid_backup = proc->pid; // Keep for logging
FastMemset(proc, 0, sizeof(Process));

// Free the slot
FreeSlot(slot);
process_count--;
cleanup_count++;

PrintKernel("[KERNEL] Process PID ");
PrintKernelInt(pid_backup);
PrintKernel(" cleaned up successfully (state now PROC_TERMINATED=0)\n");
}
}

Expand Down Expand Up @@ -597,23 +729,27 @@ void SecureKernelIntegritySubsystem(void) {
} else {
Panic("[SYSTEM] Failed to create system service.\n");
}

PrintKernelSuccess("[SYSTEM] SecureKernelIntegritySubsystem() deploying...\n");
while (1) {
Yield();

// Check for security violations
for (int i = 0; i < MAX_PROCESSES; i++) {
if ((processes[i].state == PROC_READY || processes[i].state == PROC_RUNNING) && processes[i].pid != 0) {
if ((processes[i].state == PROC_READY || processes[i].state == PROC_RUNNING) &&
processes[i].pid != 0) {
if (!ValidateToken(&processes[i].token, processes[i].pid)) {
PrintKernel("[SYSTEM] SecureKernelIntegritySubsystem found a corrupt token for PID: ");
PrintKernel("[SYSTEM] SecureKernelIntegritySubsystem found corrupt token for PID: ");
PrintKernelInt(processes[i].pid);
PrintKernel("! Terminating.\n");
processes[i].state = PROC_TERMINATED;
if (processes[i].stack) {
FreePage(processes[i].stack);
processes[i].stack = NULL;
}
process_count--;

// Use proper termination instead of direct manipulation
TerminateProcess(processes[i].pid, TERM_SECURITY, 1);
}
}
}
}

// Perform cleanup
CleanupTerminatedProcesses();
}
}
}
20 changes: 16 additions & 4 deletions Kernel/Process/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,18 @@ typedef enum {
PROC_TERMINATED = 0, // IMPORTANT: Keep this as 0 since your code expects it
PROC_READY,
PROC_RUNNING,
PROC_BLOCKED
PROC_BLOCKED,
PROC_ZOMBIE, // New: Waiting for cleanup
PROC_DYING // New: In process of termination
} ProcessState;

typedef enum {
TERM_NORMAL = 0, // Normal exit
TERM_KILLED, // Killed by another process
TERM_CRASHED, // Crashed/exception
TERM_SECURITY, // Security violation
TERM_RESOURCE // Resource exhaustion
} TerminationReason;
// Use the same structure for context switching to avoid mismatches
typedef struct Registers ProcessContext;

Expand All @@ -51,14 +60,16 @@ typedef struct {
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)
TerminationReason term_reason;
uint32_t exit_code;
uint64_t termination_time;
uint32_t parent_pid; // For process hierarchy
SecurityToken token;
MessageQueue ipc_queue;
ProcessContext context;
SchedulerNode* scheduler_node;
} Process;



typedef struct {
uint32_t process_slots[MAX_PROCESSES];
SchedulerNode* head;
Expand Down Expand Up @@ -102,5 +113,6 @@ void DumpSchedulerState(void);
void RegisterSecurityManager(uint32_t pid);
void SecureKernelIntegritySubsystem(void);
void SystemService(void);

void KillProcess(uint32_t pid);
uint64_t GetSystemTicks(void);
#endif