mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
Stage 4
This commit is contained in:
1
Makefile
1
Makefile
@@ -71,6 +71,7 @@ C_SOURCES := \
|
||||
clks/kernel/pmm.c \
|
||||
clks/kernel/heap.c \
|
||||
clks/kernel/interrupts.c \
|
||||
clks/kernel/scheduler.c \
|
||||
clks/lib/string.c \
|
||||
clks/drivers/serial/serial.c \
|
||||
clks/drivers/video/framebuffer.c \
|
||||
|
||||
20
clks/include/clks/scheduler.h
Normal file
20
clks/include/clks/scheduler.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef CLKS_SCHEDULER_H
|
||||
#define CLKS_SCHEDULER_H
|
||||
|
||||
#include <clks/task.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
struct clks_scheduler_stats {
|
||||
u32 task_count;
|
||||
u32 current_task_id;
|
||||
u64 total_timer_ticks;
|
||||
u64 context_switch_count;
|
||||
};
|
||||
|
||||
void clks_scheduler_init(void);
|
||||
clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks);
|
||||
void clks_scheduler_on_timer_tick(u64 tick);
|
||||
struct clks_scheduler_stats clks_scheduler_get_stats(void);
|
||||
const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id);
|
||||
|
||||
#endif
|
||||
25
clks/include/clks/task.h
Normal file
25
clks/include/clks/task.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef CLKS_TASK_H
|
||||
#define CLKS_TASK_H
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_TASK_NAME_MAX 32U
|
||||
|
||||
enum clks_task_state {
|
||||
CLKS_TASK_UNUSED = 0,
|
||||
CLKS_TASK_READY = 1,
|
||||
CLKS_TASK_RUNNING = 2,
|
||||
CLKS_TASK_BLOCKED = 3
|
||||
};
|
||||
|
||||
struct clks_task_descriptor {
|
||||
u32 id;
|
||||
char name[CLKS_TASK_NAME_MAX];
|
||||
enum clks_task_state state;
|
||||
u32 time_slice_ticks;
|
||||
u32 remaining_ticks;
|
||||
u64 total_ticks;
|
||||
u64 switch_count;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <clks/cpu.h>
|
||||
#include <clks/interrupts.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/scheduler.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_IDT_ENTRY_COUNT 256U
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <clks/kernel.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/pmm.h>
|
||||
#include <clks/scheduler.h>
|
||||
#include <clks/serial.h>
|
||||
#include <clks/tty.h>
|
||||
#include <clks/types.h>
|
||||
@@ -15,6 +16,7 @@ void clks_kernel_main(void) {
|
||||
const struct limine_memmap_response *boot_memmap;
|
||||
struct clks_pmm_stats pmm_stats;
|
||||
struct clks_heap_stats heap_stats;
|
||||
struct clks_scheduler_stats sched_stats;
|
||||
void *heap_probe = CLKS_NULL;
|
||||
|
||||
clks_serial_init();
|
||||
@@ -31,7 +33,7 @@ void clks_kernel_main(void) {
|
||||
clks_tty_init();
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE3 START");
|
||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE4 START");
|
||||
|
||||
if (boot_fb == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
||||
@@ -78,6 +80,19 @@ void clks_kernel_main(void) {
|
||||
clks_kfree(heap_probe);
|
||||
}
|
||||
|
||||
clks_scheduler_init();
|
||||
|
||||
if (clks_scheduler_add_kernel_task("klogd", 4U) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KLOGD TASK");
|
||||
}
|
||||
|
||||
if (clks_scheduler_add_kernel_task("kworker", 3U) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KWORKER TASK");
|
||||
}
|
||||
|
||||
sched_stats = clks_scheduler_get_stats();
|
||||
clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count);
|
||||
|
||||
clks_interrupts_init();
|
||||
clks_log(CLKS_LOG_INFO, "INT", "IDT + PIC INITIALIZED");
|
||||
|
||||
|
||||
138
clks/kernel/scheduler.c
Normal file
138
clks/kernel/scheduler.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <clks/log.h>
|
||||
#include <clks/scheduler.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_SCHED_MAX_TASKS 16U
|
||||
#define CLKS_SCHED_MIN_SLICE 1U
|
||||
|
||||
static struct clks_task_descriptor clks_tasks[CLKS_SCHED_MAX_TASKS];
|
||||
static u32 clks_task_count = 0;
|
||||
static u32 clks_current_task = 0;
|
||||
static u64 clks_total_timer_ticks = 0;
|
||||
static u64 clks_context_switch_count = 0;
|
||||
|
||||
static void clks_sched_copy_name(char *dst, const char *src) {
|
||||
u32 i = 0;
|
||||
|
||||
while (i < (CLKS_TASK_NAME_MAX - 1U) && src[i] != '\0') {
|
||||
dst[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static u32 clks_sched_next_ready_task(u32 from) {
|
||||
u32 i;
|
||||
|
||||
for (i = 1U; i <= clks_task_count; i++) {
|
||||
u32 idx = (from + i) % clks_task_count;
|
||||
|
||||
if (clks_tasks[idx].state == CLKS_TASK_READY || clks_tasks[idx].state == CLKS_TASK_RUNNING) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
return from;
|
||||
}
|
||||
|
||||
void clks_scheduler_init(void) {
|
||||
clks_memset(clks_tasks, 0, sizeof(clks_tasks));
|
||||
clks_task_count = 0;
|
||||
clks_current_task = 0;
|
||||
clks_total_timer_ticks = 0;
|
||||
clks_context_switch_count = 0;
|
||||
|
||||
clks_scheduler_add_kernel_task("idle", 1U);
|
||||
|
||||
clks_tasks[0].state = CLKS_TASK_RUNNING;
|
||||
clks_tasks[0].remaining_ticks = clks_tasks[0].time_slice_ticks;
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "SCHED", "ROUND-ROBIN ONLINE");
|
||||
}
|
||||
|
||||
clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks) {
|
||||
struct clks_task_descriptor *task;
|
||||
|
||||
if (name == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_task_count >= CLKS_SCHED_MAX_TASKS) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (time_slice_ticks < CLKS_SCHED_MIN_SLICE) {
|
||||
time_slice_ticks = CLKS_SCHED_MIN_SLICE;
|
||||
}
|
||||
|
||||
task = &clks_tasks[clks_task_count];
|
||||
task->id = clks_task_count;
|
||||
clks_sched_copy_name(task->name, name);
|
||||
task->state = CLKS_TASK_READY;
|
||||
task->time_slice_ticks = time_slice_ticks;
|
||||
task->remaining_ticks = time_slice_ticks;
|
||||
task->total_ticks = 0;
|
||||
task->switch_count = 0;
|
||||
|
||||
clks_task_count++;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_scheduler_on_timer_tick(u64 tick) {
|
||||
struct clks_task_descriptor *current;
|
||||
|
||||
if (clks_task_count == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_total_timer_ticks = tick;
|
||||
|
||||
current = &clks_tasks[clks_current_task];
|
||||
|
||||
if (current->state == CLKS_TASK_RUNNING || current->state == CLKS_TASK_READY) {
|
||||
current->total_ticks++;
|
||||
|
||||
if (current->remaining_ticks > 0U) {
|
||||
current->remaining_ticks--;
|
||||
}
|
||||
}
|
||||
|
||||
if (current->remaining_ticks == 0U) {
|
||||
u32 next = clks_sched_next_ready_task(clks_current_task);
|
||||
|
||||
current->remaining_ticks = current->time_slice_ticks;
|
||||
|
||||
if (next != clks_current_task) {
|
||||
if (current->state == CLKS_TASK_RUNNING) {
|
||||
current->state = CLKS_TASK_READY;
|
||||
}
|
||||
|
||||
clks_current_task = next;
|
||||
clks_tasks[clks_current_task].state = CLKS_TASK_RUNNING;
|
||||
clks_tasks[clks_current_task].switch_count++;
|
||||
clks_tasks[clks_current_task].remaining_ticks = clks_tasks[clks_current_task].time_slice_ticks;
|
||||
clks_context_switch_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct clks_scheduler_stats clks_scheduler_get_stats(void) {
|
||||
struct clks_scheduler_stats stats;
|
||||
|
||||
stats.task_count = clks_task_count;
|
||||
stats.current_task_id = clks_current_task;
|
||||
stats.total_timer_ticks = clks_total_timer_ticks;
|
||||
stats.context_switch_count = clks_context_switch_count;
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id) {
|
||||
if (task_id >= clks_task_count) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return &clks_tasks[task_id];
|
||||
}
|
||||
35
docs/stage4.md
Normal file
35
docs/stage4.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# CLeonOS Stage4
|
||||
|
||||
## Stage Goal
|
||||
- Add process/task scheduling foundation in CLKS.
|
||||
- Introduce task control blocks and kernel task registry.
|
||||
- Implement timer-driven round-robin time-slice scheduling logic.
|
||||
- Connect scheduler tick updates to IRQ0 interrupt path.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Kernel boots and prints `CLEONOS STAGE4 START`.
|
||||
- Scheduler initializes and logs task count.
|
||||
- At least 3 kernel tasks exist (`idle`, `klogd`, `kworker`).
|
||||
- Timer IRQ invokes scheduler tick handler without panic/reboot.
|
||||
- System stays in idle loop with interrupts and scheduler active.
|
||||
|
||||
## Build Targets
|
||||
- `make setup`
|
||||
- `make iso`
|
||||
- `make run`
|
||||
- `make debug`
|
||||
|
||||
## QEMU Command
|
||||
- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio`
|
||||
|
||||
## Common Bugs and Debugging
|
||||
- Immediate reboot after enabling interrupts:
|
||||
- Verify IDT selector uses runtime `CS` and ISR stubs are linked.
|
||||
- Scheduler task count is 0:
|
||||
- Confirm `clks_scheduler_init()` is called before idle loop.
|
||||
- Build failure on ISR symbols:
|
||||
- Ensure `interrupt_stubs.S` is included and `.S` build rule exists.
|
||||
- Build failure on scheduler symbols:
|
||||
- Ensure `scheduler.c` is in `C_SOURCES` and `scheduler.h` is included where needed.
|
||||
- No periodic scheduling activity:
|
||||
- Verify IRQ0 is unmasked and timer vector 32 path calls scheduler tick handler.
|
||||
Reference in New Issue
Block a user