This commit is contained in:
2026-04-10 20:32:03 +08:00
parent 2435452262
commit 30b2a126c5
11 changed files with 321 additions and 21 deletions

View File

@@ -92,6 +92,7 @@ C_SOURCES := \
clks/kernel/fs.c \ clks/kernel/fs.c \
clks/kernel/userland.c \ clks/kernel/userland.c \
clks/kernel/driver.c \ clks/kernel/driver.c \
clks/kernel/service.c \
clks/lib/string.c \ clks/lib/string.c \
clks/drivers/serial/serial.c \ clks/drivers/serial/serial.c \
clks/drivers/video/framebuffer.c \ clks/drivers/video/framebuffer.c \

View File

@@ -4,10 +4,13 @@
typedef unsigned long long u64; typedef unsigned long long u64;
typedef unsigned long long usize; typedef unsigned long long usize;
#define CLEONOS_SYSCALL_LOG_WRITE 0ULL #define CLEONOS_SYSCALL_LOG_WRITE 0ULL
#define CLEONOS_SYSCALL_TIMER_TICKS 1ULL #define CLEONOS_SYSCALL_TIMER_TICKS 1ULL
#define CLEONOS_SYSCALL_TASK_COUNT 2ULL #define CLEONOS_SYSCALL_TASK_COUNT 2ULL
#define CLEONOS_SYSCALL_CUR_TASK 3ULL #define CLEONOS_SYSCALL_CUR_TASK 3ULL
#define CLEONOS_SYSCALL_SERVICE_COUNT 4ULL
#define CLEONOS_SYSCALL_SERVICE_READY_COUNT 5ULL
#define CLEONOS_SYSCALL_CONTEXT_SWITCHES 6ULL
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
u64 cleonos_sys_log_write(const char *message, u64 length); u64 cleonos_sys_log_write(const char *message, u64 length);

View File

@@ -13,8 +13,10 @@ struct clks_scheduler_stats {
void clks_scheduler_init(void); void clks_scheduler_init(void);
clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks); clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks);
clks_bool clks_scheduler_add_kernel_task_ex(const char *name, u32 time_slice_ticks, clks_task_entry_fn entry);
void clks_scheduler_on_timer_tick(u64 tick); void clks_scheduler_on_timer_tick(u64 tick);
void clks_scheduler_dispatch_current(u64 tick);
struct clks_scheduler_stats clks_scheduler_get_stats(void); struct clks_scheduler_stats clks_scheduler_get_stats(void);
const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id); const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id);
#endif #endif

View File

@@ -0,0 +1,36 @@
#ifndef CLKS_SERVICE_H
#define CLKS_SERVICE_H
#include <clks/types.h>
#define CLKS_SERVICE_NAME_MAX 24U
enum clks_service_id {
CLKS_SERVICE_LOG = 1,
CLKS_SERVICE_MEM = 2,
CLKS_SERVICE_FS = 3,
CLKS_SERVICE_DRIVER = 4,
CLKS_SERVICE_SCHED = 5,
};
enum clks_service_state {
CLKS_SERVICE_STATE_OFFLINE = 0,
CLKS_SERVICE_STATE_READY = 1,
CLKS_SERVICE_STATE_DEGRADED = 2,
};
struct clks_service_info {
u32 id;
char name[CLKS_SERVICE_NAME_MAX];
enum clks_service_state state;
u64 heartbeat_count;
u64 last_heartbeat_tick;
};
void clks_service_init(void);
clks_bool clks_service_heartbeat(u32 service_id, u64 tick);
u64 clks_service_count(void);
u64 clks_service_ready_count(void);
clks_bool clks_service_get(u32 service_id, struct clks_service_info *out_info);
#endif

View File

@@ -3,13 +3,16 @@
#include <clks/types.h> #include <clks/types.h>
#define CLKS_SYSCALL_LOG_WRITE 0ULL #define CLKS_SYSCALL_LOG_WRITE 0ULL
#define CLKS_SYSCALL_TIMER_TICKS 1ULL #define CLKS_SYSCALL_TIMER_TICKS 1ULL
#define CLKS_SYSCALL_TASK_COUNT 2ULL #define CLKS_SYSCALL_TASK_COUNT 2ULL
#define CLKS_SYSCALL_CURRENT_TASK_ID 3ULL #define CLKS_SYSCALL_CURRENT_TASK_ID 3ULL
#define CLKS_SYSCALL_SERVICE_COUNT 4ULL
#define CLKS_SYSCALL_SERVICE_READY_COUNT 5ULL
#define CLKS_SYSCALL_CONTEXT_SWITCHES 6ULL
void clks_syscall_init(void); void clks_syscall_init(void);
u64 clks_syscall_dispatch(void *frame_ptr); u64 clks_syscall_dispatch(void *frame_ptr);
u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2);
#endif #endif

View File

@@ -5,6 +5,8 @@
#define CLKS_TASK_NAME_MAX 32U #define CLKS_TASK_NAME_MAX 32U
typedef void (*clks_task_entry_fn)(u64 tick);
enum clks_task_state { enum clks_task_state {
CLKS_TASK_UNUSED = 0, CLKS_TASK_UNUSED = 0,
CLKS_TASK_READY = 1, CLKS_TASK_READY = 1,
@@ -20,6 +22,9 @@ struct clks_task_descriptor {
u32 remaining_ticks; u32 remaining_ticks;
u64 total_ticks; u64 total_ticks;
u64 switch_count; u64 switch_count;
u64 run_count;
u64 last_run_tick;
clks_task_entry_fn entry;
}; };
#endif #endif

View File

@@ -11,11 +11,46 @@
#include <clks/pmm.h> #include <clks/pmm.h>
#include <clks/scheduler.h> #include <clks/scheduler.h>
#include <clks/serial.h> #include <clks/serial.h>
#include <clks/service.h>
#include <clks/syscall.h> #include <clks/syscall.h>
#include <clks/tty.h> #include <clks/tty.h>
#include <clks/types.h> #include <clks/types.h>
#include <clks/userland.h> #include <clks/userland.h>
static void clks_task_klogd(u64 tick) {
static u64 last_emit = 0ULL;
clks_service_heartbeat(CLKS_SERVICE_LOG, tick);
if (tick - last_emit >= 1000ULL) {
clks_log_hex(CLKS_LOG_DEBUG, "TASK", "KLOGD_TICK", tick);
last_emit = tick;
}
}
static void clks_task_kworker(u64 tick) {
static u32 phase = 0U;
clks_service_heartbeat(CLKS_SERVICE_SCHED, tick);
switch (phase) {
case 0U:
clks_service_heartbeat(CLKS_SERVICE_MEM, tick);
break;
case 1U:
clks_service_heartbeat(CLKS_SERVICE_FS, tick);
break;
case 2U:
clks_service_heartbeat(CLKS_SERVICE_DRIVER, tick);
break;
default:
clks_service_heartbeat(CLKS_SERVICE_LOG, tick);
break;
}
phase = (phase + 1U) & 3U;
}
void clks_kernel_main(void) { void clks_kernel_main(void) {
const struct limine_framebuffer *boot_fb; const struct limine_framebuffer *boot_fb;
const struct limine_memmap_response *boot_memmap; const struct limine_memmap_response *boot_memmap;
@@ -41,7 +76,7 @@ void clks_kernel_main(void) {
clks_tty_init(); clks_tty_init();
} }
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE8 START"); clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE9 START");
if (boot_fb == CLKS_NULL) { if (boot_fb == CLKS_NULL) {
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
@@ -112,17 +147,19 @@ void clks_kernel_main(void) {
clks_scheduler_init(); clks_scheduler_init();
if (clks_scheduler_add_kernel_task("klogd", 4U) == CLKS_FALSE) { if (clks_scheduler_add_kernel_task_ex("klogd", 4U, clks_task_klogd) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KLOGD TASK"); clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KLOGD TASK");
} }
if (clks_scheduler_add_kernel_task("kworker", 3U) == CLKS_FALSE) { if (clks_scheduler_add_kernel_task_ex("kworker", 3U, clks_task_kworker) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KWORKER TASK"); clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KWORKER TASK");
} }
sched_stats = clks_scheduler_get_stats(); sched_stats = clks_scheduler_get_stats();
clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count); clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count);
clks_service_init();
clks_elfrunner_init(); clks_elfrunner_init();
if (clks_elfrunner_probe_kernel_executable() == CLKS_FALSE) { if (clks_elfrunner_probe_kernel_executable() == CLKS_FALSE) {

View File

@@ -44,7 +44,7 @@ void clks_scheduler_init(void) {
clks_total_timer_ticks = 0; clks_total_timer_ticks = 0;
clks_context_switch_count = 0; clks_context_switch_count = 0;
clks_scheduler_add_kernel_task("idle", 1U); clks_scheduler_add_kernel_task_ex("idle", 1U, CLKS_NULL);
clks_tasks[0].state = CLKS_TASK_RUNNING; clks_tasks[0].state = CLKS_TASK_RUNNING;
clks_tasks[0].remaining_ticks = clks_tasks[0].time_slice_ticks; clks_tasks[0].remaining_ticks = clks_tasks[0].time_slice_ticks;
@@ -52,7 +52,7 @@ void clks_scheduler_init(void) {
clks_log(CLKS_LOG_INFO, "SCHED", "ROUND-ROBIN ONLINE"); clks_log(CLKS_LOG_INFO, "SCHED", "ROUND-ROBIN ONLINE");
} }
clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks) { clks_bool clks_scheduler_add_kernel_task_ex(const char *name, u32 time_slice_ticks, clks_task_entry_fn entry) {
struct clks_task_descriptor *task; struct clks_task_descriptor *task;
if (name == CLKS_NULL) { if (name == CLKS_NULL) {
@@ -73,13 +73,42 @@ clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks)
task->state = CLKS_TASK_READY; task->state = CLKS_TASK_READY;
task->time_slice_ticks = time_slice_ticks; task->time_slice_ticks = time_slice_ticks;
task->remaining_ticks = time_slice_ticks; task->remaining_ticks = time_slice_ticks;
task->total_ticks = 0; task->total_ticks = 0ULL;
task->switch_count = 0; task->switch_count = 0ULL;
task->run_count = 0ULL;
task->last_run_tick = 0ULL;
task->entry = entry;
clks_task_count++; clks_task_count++;
return CLKS_TRUE; return CLKS_TRUE;
} }
clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks) {
return clks_scheduler_add_kernel_task_ex(name, time_slice_ticks, CLKS_NULL);
}
void clks_scheduler_dispatch_current(u64 tick) {
struct clks_task_descriptor *current;
if (clks_task_count == 0U) {
return;
}
current = &clks_tasks[clks_current_task];
if (current->state != CLKS_TASK_RUNNING && current->state != CLKS_TASK_READY) {
return;
}
current->state = CLKS_TASK_RUNNING;
current->run_count++;
current->last_run_tick = tick;
if (current->entry != CLKS_NULL) {
current->entry(tick);
}
}
void clks_scheduler_on_timer_tick(u64 tick) { void clks_scheduler_on_timer_tick(u64 tick) {
struct clks_task_descriptor *current; struct clks_task_descriptor *current;
@@ -88,7 +117,6 @@ void clks_scheduler_on_timer_tick(u64 tick) {
} }
clks_total_timer_ticks = tick; clks_total_timer_ticks = tick;
current = &clks_tasks[clks_current_task]; current = &clks_tasks[clks_current_task];
if (current->state == CLKS_TASK_RUNNING || current->state == CLKS_TASK_READY) { if (current->state == CLKS_TASK_RUNNING || current->state == CLKS_TASK_READY) {
@@ -116,6 +144,8 @@ void clks_scheduler_on_timer_tick(u64 tick) {
clks_context_switch_count++; clks_context_switch_count++;
} }
} }
clks_scheduler_dispatch_current(tick);
} }
struct clks_scheduler_stats clks_scheduler_get_stats(void) { struct clks_scheduler_stats clks_scheduler_get_stats(void) {
@@ -135,4 +165,4 @@ const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id) {
} }
return &clks_tasks[task_id]; return &clks_tasks[task_id];
} }

138
clks/kernel/service.c Normal file
View File

@@ -0,0 +1,138 @@
#include <clks/driver.h>
#include <clks/fs.h>
#include <clks/heap.h>
#include <clks/log.h>
#include <clks/scheduler.h>
#include <clks/service.h>
#include <clks/string.h>
#include <clks/types.h>
#define CLKS_SERVICE_MAX 8U
static struct clks_service_info clks_services[CLKS_SERVICE_MAX];
static u64 clks_service_used = 0ULL;
static void clks_service_copy_name(char *dst, usize dst_size, const char *src) {
usize i = 0U;
if (dst == CLKS_NULL || dst_size == 0U) {
return;
}
while (i + 1U < dst_size && src[i] != '\0') {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
static i32 clks_service_find_index(u32 service_id) {
u64 i;
for (i = 0ULL; i < clks_service_used; i++) {
if (clks_services[i].id == service_id) {
return (i32)i;
}
}
return -1;
}
static clks_bool clks_service_register(u32 id, const char *name, enum clks_service_state state) {
struct clks_service_info *slot;
if (clks_service_used >= CLKS_SERVICE_MAX) {
return CLKS_FALSE;
}
slot = &clks_services[clks_service_used];
clks_memset(slot, 0, sizeof(*slot));
slot->id = id;
clks_service_copy_name(slot->name, sizeof(slot->name), name);
slot->state = state;
slot->heartbeat_count = 0ULL;
slot->last_heartbeat_tick = 0ULL;
clks_service_used++;
return CLKS_TRUE;
}
void clks_service_init(void) {
struct clks_heap_stats heap_stats;
clks_memset(clks_services, 0, sizeof(clks_services));
clks_service_used = 0ULL;
heap_stats = clks_heap_get_stats();
clks_service_register(CLKS_SERVICE_LOG, "log", CLKS_SERVICE_STATE_READY);
clks_service_register(CLKS_SERVICE_MEM,
"memory",
(heap_stats.total_bytes > 0U) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_FS,
"filesystem",
(clks_fs_is_ready() == CLKS_TRUE) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_DRIVER,
"driver",
(clks_driver_count() > 0ULL) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_SCHED,
"scheduler",
CLKS_SERVICE_STATE_READY);
clks_log(CLKS_LOG_INFO, "SRV", "KERNEL SERVICES ONLINE");
clks_log_hex(CLKS_LOG_INFO, "SRV", "COUNT", clks_service_count());
clks_log_hex(CLKS_LOG_INFO, "SRV", "READY", clks_service_ready_count());
}
clks_bool clks_service_heartbeat(u32 service_id, u64 tick) {
i32 idx = clks_service_find_index(service_id);
if (idx < 0) {
return CLKS_FALSE;
}
clks_services[(u32)idx].heartbeat_count++;
clks_services[(u32)idx].last_heartbeat_tick = tick;
if (clks_services[(u32)idx].state == CLKS_SERVICE_STATE_OFFLINE) {
clks_services[(u32)idx].state = CLKS_SERVICE_STATE_READY;
}
return CLKS_TRUE;
}
u64 clks_service_count(void) {
return clks_service_used;
}
u64 clks_service_ready_count(void) {
u64 i;
u64 ready = 0ULL;
for (i = 0ULL; i < clks_service_used; i++) {
if (clks_services[i].state == CLKS_SERVICE_STATE_READY) {
ready++;
}
}
return ready;
}
clks_bool clks_service_get(u32 service_id, struct clks_service_info *out_info) {
i32 idx;
if (out_info == CLKS_NULL) {
return CLKS_FALSE;
}
idx = clks_service_find_index(service_id);
if (idx < 0) {
return CLKS_FALSE;
}
*out_info = clks_services[(u32)idx];
return CLKS_TRUE;
}

View File

@@ -1,6 +1,7 @@
#include <clks/interrupts.h> #include <clks/interrupts.h>
#include <clks/log.h> #include <clks/log.h>
#include <clks/scheduler.h> #include <clks/scheduler.h>
#include <clks/service.h>
#include <clks/syscall.h> #include <clks/syscall.h>
#include <clks/types.h> #include <clks/types.h>
@@ -83,6 +84,14 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
struct clks_scheduler_stats stats = clks_scheduler_get_stats(); struct clks_scheduler_stats stats = clks_scheduler_get_stats();
return stats.current_task_id; return stats.current_task_id;
} }
case CLKS_SYSCALL_SERVICE_COUNT:
return clks_service_count();
case CLKS_SYSCALL_SERVICE_READY_COUNT:
return clks_service_ready_count();
case CLKS_SYSCALL_CONTEXT_SWITCHES: {
struct clks_scheduler_stats stats = clks_scheduler_get_stats();
return stats.context_switch_count;
}
default: default:
return (u64)-1; return (u64)-1;
} }
@@ -99,4 +108,4 @@ u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2) {
); );
return ret; return ret;
} }

36
docs/stage9.md Normal file
View File

@@ -0,0 +1,36 @@
# CLeonOS Stage9
## Stage Goal
- Add kernel service layer to represent core kernel capabilities.
- Extend scheduler with real task execution callbacks on timer ticks.
- Connect worker tasks (`klogd`, `kworker`) to service heartbeat updates.
- Extend syscall interface with service and scheduler runtime counters.
## Acceptance Criteria
- Kernel boots and prints `CLEONOS STAGE9 START`.
- Service framework logs `KERNEL SERVICES ONLINE`.
- Service counters (`COUNT`, `READY`) are logged.
- Scheduler still reports task count and runs without panic.
- Syscall layer remains online and returns valid ticks after interrupt init.
## Build Targets
- `make setup`
- `make userapps`
- `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
- `undefined reference` for service APIs:
- Ensure `clks/kernel/service.c` is listed in `C_SOURCES`.
- Task callbacks never run:
- Confirm timer IRQ path still calls `clks_scheduler_on_timer_tick()`.
- Service count is 0:
- Verify `clks_service_init()` is called after scheduler/driver/fs init.
- Syscall service counters return `-1`:
- Check syscall IDs in kernel and user headers match.
- Boot panic after Stage9 merge:
- Re-check `kmain` init order: FS -> userland -> driver -> scheduler -> service -> interrupts.