From 77400d8f5a309e4ec7d2a5dd9c2b787177075f44 Mon Sep 17 00:00:00 2001 From: Gregory Bowne Date: Wed, 19 Nov 2025 08:41:03 -0800 Subject: [PATCH] Update scheduler.c old scheduler might not work on x86 IA-32 32 bit --- kernel/scheduler.c | 60 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/kernel/scheduler.c b/kernel/scheduler.c index cdb8812..8514c3c 100644 --- a/kernel/scheduler.c +++ b/kernel/scheduler.c @@ -1,7 +1,12 @@ #include "scheduler.h" #include +// Defined in context_switch.s +extern void ctx_switch(uint32_t **old_sp_ptr, uint32_t *new_sp); + static task_t tasks[MAX_TASKS]; + +// Stack memory area. Note: x86 Stacks grow DOWN from high to low addresses. static uint32_t task_stacks[MAX_TASKS][STACK_SIZE / sizeof(uint32_t)]; static int task_count = 0; @@ -9,7 +14,6 @@ static task_t *task_list = NULL; static task_t *current_task = NULL; void scheduler_init() { - // Initialize task list, etc. task_list = NULL; current_task = NULL; task_count = 0; @@ -20,16 +24,42 @@ void scheduler_add_task(void (*entry)(void)) { task_t *new_task = &tasks[task_count]; new_task->id = task_count; - new_task->entry = entry; - // Simulate a stack pointer pointing to the "top" of the stack - new_task->stack_ptr = &task_stacks[task_count][STACK_SIZE / sizeof(uint32_t) - 1]; + // 1. Calculate the top of the stack (High Address) + // We point to the very end of the array. + uint32_t *sp = &task_stacks[task_count][STACK_SIZE / sizeof(uint32_t)]; + // 2. "Forge" the stack frame to look like ctx_switch saved it. + // We push values onto the stack by decrementing the pointer and writing. + + // --- Return Address (EIP) --- + sp--; + *sp = (uint32_t)entry; // When ctx_switch does 'ret', it pops this and jumps to 'entry' + + // --- EFLAGS --- + sp--; + *sp = 0x00000202; // Reserved bit set, Interrupts Enabled (IF=1). Important! + + // --- General Purpose Registers (PUSHA/POPA layout) --- + // Order: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI + // We initialize them to 0 or meaningful values. + sp--; *sp = 0; // EAX + sp--; *sp = 0; // ECX + sp--; *sp = 0; // EDX + sp--; *sp = 0; // EBX + sp--; *sp = 0; // ESP (Ignored by POPA) + sp--; *sp = 0; // EBP + sp--; *sp = 0; // ESI + sp--; *sp = 0; // EDI + + // Save this final stack location to the TCB + new_task->stack_ptr = sp; new_task->next = NULL; - // Add to task list + // 3. Add to linked list if (task_list == NULL) { task_list = new_task; + current_task = new_task; // Make sure we have a current task to start } else { task_t *tail = task_list; while (tail->next) { @@ -42,21 +72,25 @@ void scheduler_add_task(void (*entry)(void)) { } void scheduler_schedule() { - // Very basic round-robin switch - if (current_task && current_task->next) { + if (!current_task) return; + + task_t *prev = current_task; + + // Round-robin logic + if (current_task->next) { current_task = current_task->next; } else { - current_task = task_list; // Loop back + current_task = task_list; } - // Call context switch or simulate yielding to current_task - // In real system: context_switch_to(current_task) - if (current_task && current_task->entry) { - current_task->entry(); // Simulate switching by calling + // Perform the ACTUAL context switch + // We pass the address of the previous task's stack pointer storage + // and the value of the new task's stack pointer. + if (prev != current_task) { + ctx_switch(&prev->stack_ptr, current_task->stack_ptr); } } void scheduler_yield() { - // Stub: manually call schedule for cooperative multitasking scheduler_schedule(); }