2026-06-26 20:05:01 -05:00
|
|
|
#include <lib/tasks.h>
|
2026-07-01 20:00:22 -05:00
|
|
|
#include <lib/print.h>
|
2026-06-26 20:05:01 -05:00
|
|
|
#include <lib/memory.h>
|
|
|
|
|
|
|
|
|
|
#include <memory/mm.h>
|
|
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
|
2026-06-28 17:58:58 -05:00
|
|
|
#include "common.h"
|
2026-06-26 20:05:01 -05:00
|
|
|
#include "process.h"
|
|
|
|
|
#include "scheduler.h"
|
2026-06-30 19:26:31 -05:00
|
|
|
#include "gdt.h"
|
2026-06-26 20:05:01 -05:00
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
static process_t* process_table = NULL;
|
|
|
|
|
static process_t* current_process = NULL;
|
|
|
|
|
static process_t* idle_task = NULL;
|
2026-06-26 20:05:01 -05:00
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
static int total_processes = 0;
|
2026-06-26 20:05:01 -05:00
|
|
|
|
2026-07-07 18:52:22 -05:00
|
|
|
void lock_scheduler() {
|
2026-06-28 17:58:58 -05:00
|
|
|
disable_interrupts();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-07 18:52:22 -05:00
|
|
|
void unlock_scheduler() {
|
2026-06-28 17:58:58 -05:00
|
|
|
enable_interrupts();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t switch_context(uint32_t current_esp) {
|
2026-07-07 00:13:24 -05:00
|
|
|
current_process->esp = current_esp;
|
2026-06-26 20:05:01 -05:00
|
|
|
|
2026-07-07 18:52:22 -05:00
|
|
|
process_t* next_process = current_process->sched_next;
|
2026-06-26 20:05:01 -05:00
|
|
|
int found_ready = 0;
|
2026-07-07 18:52:22 -05:00
|
|
|
while (next_process != NULL) {
|
2026-07-07 00:13:24 -05:00
|
|
|
if (next_process != idle_task && next_process->state == STATE_READY) {
|
2026-06-26 20:05:01 -05:00
|
|
|
found_ready = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (next_process == current_process) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-07-07 18:52:22 -05:00
|
|
|
|
|
|
|
|
next_process = (process_t*)next_process->sched_next;
|
2026-06-26 20:05:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found_ready) {
|
2026-07-07 18:52:22 -05:00
|
|
|
if (current_process && current_process->state == STATE_READY) {
|
2026-06-26 20:05:01 -05:00
|
|
|
next_process = current_process;
|
|
|
|
|
} else {
|
2026-07-07 00:13:24 -05:00
|
|
|
next_process = idle_task;
|
2026-06-26 20:05:01 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_process = next_process;
|
|
|
|
|
|
2026-07-04 00:26:20 -05:00
|
|
|
uint32_t current_cr3 = fetch_cr3();
|
2026-07-07 00:13:24 -05:00
|
|
|
if (current_cr3 != current_process->cr3) {
|
|
|
|
|
load_pd((void*)current_process->cr3);
|
2026-07-07 18:52:22 -05:00
|
|
|
flush_tlb();
|
2026-07-01 20:00:22 -05:00
|
|
|
}
|
2026-06-30 19:26:31 -05:00
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
if (current_process->flags & PROCESS_FLAG_USER) {
|
|
|
|
|
tss.esp0 = current_process->kstack_top;
|
2026-06-26 20:05:01 -05:00
|
|
|
}
|
2026-07-08 19:11:39 -05:00
|
|
|
|
|
|
|
|
|
2026-07-04 01:59:19 -05:00
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
return current_process->esp;
|
2026-06-26 20:05:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void init_scheduler() {
|
2026-07-07 00:13:24 -05:00
|
|
|
process_t* root = kalloc(sizeof(process_t));
|
|
|
|
|
root->pid = 0;
|
|
|
|
|
root->esp = 0;
|
|
|
|
|
root->cr3 = fetch_cr3();
|
|
|
|
|
root->state = STATE_READY;
|
|
|
|
|
root->sleep = 0;
|
|
|
|
|
root->flags = PROCESS_FLAG_KERNEL;
|
|
|
|
|
root->sched_next = NULL;
|
|
|
|
|
|
|
|
|
|
current_process = root;
|
|
|
|
|
idle_task = root;
|
|
|
|
|
process_table = root;
|
|
|
|
|
|
|
|
|
|
total_processes = 1;
|
2026-06-26 20:05:01 -05:00
|
|
|
}
|
|
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
void init_task (
|
|
|
|
|
process_t* process,
|
|
|
|
|
uint32_t entry_point,
|
|
|
|
|
uint32_t cr3,
|
|
|
|
|
int user,
|
|
|
|
|
uint32_t u_esp
|
|
|
|
|
) {
|
|
|
|
|
process->pid = get_next_pid();
|
2026-06-26 20:05:01 -05:00
|
|
|
process->cr3 = cr3;
|
|
|
|
|
process->state = STATE_READY;
|
|
|
|
|
process->sleep = 0;
|
2026-07-01 20:00:22 -05:00
|
|
|
process->flags = user ? PROCESS_FLAG_USER : PROCESS_FLAG_KERNEL;
|
2026-07-04 00:26:20 -05:00
|
|
|
total_processes++;
|
2026-06-26 20:05:01 -05:00
|
|
|
|
2026-07-01 20:00:22 -05:00
|
|
|
void* kstack_bottom = kalloc(PAGE_SIZE);
|
|
|
|
|
uint32_t kstack_top = (uint32_t)kstack_bottom + PAGE_SIZE;
|
|
|
|
|
process->kstack_top = kstack_top;
|
2026-06-30 19:26:31 -05:00
|
|
|
|
2026-07-01 20:00:22 -05:00
|
|
|
uint32_t* esp = (uint32_t*)kstack_top;
|
2026-06-30 19:26:31 -05:00
|
|
|
if (user) {
|
|
|
|
|
*(--esp) = 0x23; // User Data Segment (SS) with RPL 3 (0x20 | 3)
|
2026-07-03 22:25:24 -05:00
|
|
|
*(--esp) = u_esp; // User Stack Pointer (ESP) - location mapped in user space
|
2026-07-04 01:59:19 -05:00
|
|
|
*(--esp) = 0x202; // EFLAGS (Interrupts enabled)
|
2026-06-30 19:26:31 -05:00
|
|
|
*(--esp) = 0x1B; // User Code Segment (CS) with RPL 3 (0x18 | 3)
|
|
|
|
|
*(--esp) = entry_point; // EIP
|
|
|
|
|
} else {
|
|
|
|
|
// IRET values for Ring 0
|
2026-07-04 01:59:19 -05:00
|
|
|
*(--esp) = 0x202; // EFLAGS
|
2026-06-30 19:26:31 -05:00
|
|
|
*(--esp) = 0x08; // Kernel Code Segment (CS)
|
|
|
|
|
*(--esp) = entry_point; // EIP
|
|
|
|
|
}
|
2026-06-26 20:05:01 -05:00
|
|
|
|
|
|
|
|
*(--esp) = 0; // EAX
|
|
|
|
|
*(--esp) = 0; // ECX
|
|
|
|
|
*(--esp) = 0; // EDX
|
|
|
|
|
*(--esp) = 0; // EBX
|
|
|
|
|
*(--esp) = 0; // ESP
|
|
|
|
|
*(--esp) = 0; // EBP
|
|
|
|
|
*(--esp) = 0; // ESI
|
|
|
|
|
*(--esp) = 0; // EDI
|
|
|
|
|
|
2026-07-04 01:59:19 -05:00
|
|
|
if (user) {
|
|
|
|
|
*(--esp) = 0x23; // User Data Segment Selector (RPL 3)
|
|
|
|
|
} else {
|
|
|
|
|
*(--esp) = 0x10; // Kernel Data Segment Selector (RPL 0)
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-26 20:05:01 -05:00
|
|
|
process->esp = (uint32_t)esp;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
int get_next_pid() {
|
|
|
|
|
int pid = total_processes;
|
|
|
|
|
total_processes++;
|
|
|
|
|
return pid;
|
2026-06-29 17:00:07 -05:00
|
|
|
}
|
|
|
|
|
|
2026-07-07 00:13:24 -05:00
|
|
|
void add_task(process_t* task) {
|
|
|
|
|
if (!task) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (process_table->sched_next == NULL) {
|
|
|
|
|
process_table->sched_next = task;
|
|
|
|
|
task->sched_next = process_table;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
process_t* curr = process_table;
|
|
|
|
|
while (curr->sched_next != process_table) {
|
|
|
|
|
curr = curr->sched_next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
curr->sched_next = task;
|
|
|
|
|
task->sched_next = process_table;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
process_t* current_task() {
|
|
|
|
|
process_t* rtn = current_process;
|
|
|
|
|
return rtn;
|
2026-07-06 22:13:57 -05:00
|
|
|
}
|
|
|
|
|
|
2026-06-28 17:58:58 -05:00
|
|
|
void sleep(uint32_t ms) {
|
|
|
|
|
if (ms == 0) return;
|
2026-07-07 00:13:24 -05:00
|
|
|
current_process->sleep = ms;
|
|
|
|
|
current_process->state = STATE_SLEEPING;
|
2026-06-26 20:05:01 -05:00
|
|
|
yield();
|
2026-06-28 17:58:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void exit() {
|
2026-07-07 00:13:24 -05:00
|
|
|
current_process->state = STATE_DEAD;
|
2026-06-28 17:58:58 -05:00
|
|
|
yield(); // yield forever
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-06 22:13:57 -05:00
|
|
|
void wake(process_t* task) {
|
|
|
|
|
if (task->state == STATE_SLEEPING || task->state == STATE_BLOCKED) {
|
|
|
|
|
task->state = STATE_READY;
|
|
|
|
|
}
|
|
|
|
|
}
|