mirror of
https://github.com/gbowne1/ClassicOS.git
synced 2025-11-22 08:35:27 -08:00
Update scheduler.c
old scheduler might not work on x86 IA-32 32 bit
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
#include "scheduler.h"
|
||||
#include <stddef.h>
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user