From ae29f2b5cf380fa041bff939d13b42acd15572b2 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Fri, 10 Apr 2026 21:10:16 +0800 Subject: [PATCH] Stage 12 --- cleonos/c/include/cleonos_syscall.h | 12 ++++- cleonos/c/src/syscall.c | 22 ++++++++- clks/include/clks/service.h | 1 + clks/include/clks/syscall.h | 7 ++- clks/include/clks/userland.h | 6 +++ clks/kernel/kmain.c | 42 ++++++++++++++-- clks/kernel/service.c | 4 ++ clks/kernel/syscall.c | 13 ++++- clks/kernel/userland.c | 77 ++++++++++++++++++++++++++++- docs/stage12.md | 45 +++++++++++++++++ 10 files changed, 219 insertions(+), 10 deletions(-) create mode 100644 docs/stage12.md diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 19805a2..1e3cb01 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -22,6 +22,11 @@ typedef unsigned long long usize; #define CLEONOS_SYSCALL_EXEC_PATH 13ULL #define CLEONOS_SYSCALL_EXEC_REQUESTS 14ULL #define CLEONOS_SYSCALL_EXEC_SUCCESS 15ULL +#define CLEONOS_SYSCALL_USER_SHELL_READY 16ULL +#define CLEONOS_SYSCALL_USER_EXEC_REQUESTED 17ULL +#define CLEONOS_SYSCALL_USER_LAUNCH_TRIES 18ULL +#define CLEONOS_SYSCALL_USER_LAUNCH_OK 19ULL +#define CLEONOS_SYSCALL_USER_LAUNCH_FAIL 20ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); @@ -34,5 +39,10 @@ u64 cleonos_sys_fs_read(const char *path, char *out_buffer, u64 buffer_size); u64 cleonos_sys_exec_path(const char *path); u64 cleonos_sys_exec_request_count(void); u64 cleonos_sys_exec_success_count(void); +u64 cleonos_sys_user_shell_ready(void); +u64 cleonos_sys_user_exec_requested(void); +u64 cleonos_sys_user_launch_tries(void); +u64 cleonos_sys_user_launch_ok(void); +u64 cleonos_sys_user_launch_fail(void); -#endif \ No newline at end of file +#endif diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index 3166542..e2ed35d 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -51,4 +51,24 @@ u64 cleonos_sys_exec_request_count(void) { u64 cleonos_sys_exec_success_count(void) { return cleonos_syscall(CLEONOS_SYSCALL_EXEC_SUCCESS, 0ULL, 0ULL, 0ULL); -} \ No newline at end of file +} + +u64 cleonos_sys_user_shell_ready(void) { + return cleonos_syscall(CLEONOS_SYSCALL_USER_SHELL_READY, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_user_exec_requested(void) { + return cleonos_syscall(CLEONOS_SYSCALL_USER_EXEC_REQUESTED, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_user_launch_tries(void) { + return cleonos_syscall(CLEONOS_SYSCALL_USER_LAUNCH_TRIES, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_user_launch_ok(void) { + return cleonos_syscall(CLEONOS_SYSCALL_USER_LAUNCH_OK, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_user_launch_fail(void) { + return cleonos_syscall(CLEONOS_SYSCALL_USER_LAUNCH_FAIL, 0ULL, 0ULL, 0ULL); +} diff --git a/clks/include/clks/service.h b/clks/include/clks/service.h index 9c01455..8b04d3e 100644 --- a/clks/include/clks/service.h +++ b/clks/include/clks/service.h @@ -12,6 +12,7 @@ enum clks_service_id { CLKS_SERVICE_DRIVER = 4, CLKS_SERVICE_SCHED = 5, CLKS_SERVICE_KELF = 6, + CLKS_SERVICE_USER = 7, }; enum clks_service_state { diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index 7716355..6ebb9f1 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -19,9 +19,14 @@ #define CLKS_SYSCALL_EXEC_PATH 13ULL #define CLKS_SYSCALL_EXEC_REQUESTS 14ULL #define CLKS_SYSCALL_EXEC_SUCCESS 15ULL +#define CLKS_SYSCALL_USER_SHELL_READY 16ULL +#define CLKS_SYSCALL_USER_EXEC_REQUESTED 17ULL +#define CLKS_SYSCALL_USER_LAUNCH_TRIES 18ULL +#define CLKS_SYSCALL_USER_LAUNCH_OK 19ULL +#define CLKS_SYSCALL_USER_LAUNCH_FAIL 20ULL void clks_syscall_init(void); u64 clks_syscall_dispatch(void *frame_ptr); u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2); -#endif \ No newline at end of file +#endif diff --git a/clks/include/clks/userland.h b/clks/include/clks/userland.h index 8cf949c..d621004 100644 --- a/clks/include/clks/userland.h +++ b/clks/include/clks/userland.h @@ -4,5 +4,11 @@ #include clks_bool clks_userland_init(void); +void clks_userland_tick(u64 tick); +clks_bool clks_userland_shell_ready(void); +clks_bool clks_userland_shell_exec_requested(void); +u64 clks_userland_launch_attempts(void); +u64 clks_userland_launch_success(void); +u64 clks_userland_launch_failures(void); #endif diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index f73c1e8..4479ce2 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -58,7 +58,12 @@ static void clks_task_kelfd(u64 tick) { clks_kelf_tick(tick); } -static void clks_stage11_syscall_probe(void) { +static void clks_task_usrd(u64 tick) { + clks_service_heartbeat(CLKS_SERVICE_USER, tick); + clks_userland_tick(tick); +} + +static void clks_stage12_syscall_probe(void) { char child_name[96]; char read_buf[160]; u64 root_children; @@ -109,6 +114,27 @@ static void clks_stage11_syscall_probe(void) { "EXEC", "SUCCESS", clks_syscall_invoke_kernel(CLKS_SYSCALL_EXEC_SUCCESS, 0ULL, 0ULL, 0ULL)); + + clks_log_hex(CLKS_LOG_INFO, + "USER", + "SHELL_READY", + clks_syscall_invoke_kernel(CLKS_SYSCALL_USER_SHELL_READY, 0ULL, 0ULL, 0ULL)); + clks_log_hex(CLKS_LOG_INFO, + "USER", + "EXEC_REQUESTED", + clks_syscall_invoke_kernel(CLKS_SYSCALL_USER_EXEC_REQUESTED, 0ULL, 0ULL, 0ULL)); + clks_log_hex(CLKS_LOG_INFO, + "USER", + "LAUNCH_TRIES", + clks_syscall_invoke_kernel(CLKS_SYSCALL_USER_LAUNCH_TRIES, 0ULL, 0ULL, 0ULL)); + clks_log_hex(CLKS_LOG_INFO, + "USER", + "LAUNCH_OK", + clks_syscall_invoke_kernel(CLKS_SYSCALL_USER_LAUNCH_OK, 0ULL, 0ULL, 0ULL)); + clks_log_hex(CLKS_LOG_INFO, + "USER", + "LAUNCH_FAIL", + clks_syscall_invoke_kernel(CLKS_SYSCALL_USER_LAUNCH_FAIL, 0ULL, 0ULL, 0ULL)); } void clks_kernel_main(void) { @@ -136,7 +162,7 @@ void clks_kernel_main(void) { clks_tty_init(); } - clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE11 START"); + clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE12 START"); if (boot_fb == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); @@ -198,6 +224,8 @@ void clks_kernel_main(void) { clks_cpu_halt_forever(); } + clks_exec_init(); + if (clks_userland_init() == CLKS_FALSE) { clks_log(CLKS_LOG_ERROR, "USER", "USERLAND INIT FAILED"); clks_cpu_halt_forever(); @@ -205,7 +233,6 @@ void clks_kernel_main(void) { clks_driver_init(); clks_kelf_init(); - clks_exec_init(); clks_scheduler_init(); @@ -221,6 +248,10 @@ void clks_kernel_main(void) { clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KELFD TASK"); } + if (clks_scheduler_add_kernel_task_ex("usrd", 2U, clks_task_usrd) == CLKS_FALSE) { + clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD USRD TASK"); + } + sched_stats = clks_scheduler_get_stats(); clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count); @@ -240,10 +271,11 @@ void clks_kernel_main(void) { syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL); clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks); - clks_stage11_syscall_probe(); + clks_stage12_syscall_probe(); clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY"); clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER"); clks_cpu_halt_forever(); -} \ No newline at end of file +} + diff --git a/clks/kernel/service.c b/clks/kernel/service.c index 750d76f..7079aab 100644 --- a/clks/kernel/service.c +++ b/clks/kernel/service.c @@ -7,6 +7,7 @@ #include #include #include +#include #define CLKS_SERVICE_MAX 8U @@ -84,6 +85,9 @@ void clks_service_init(void) { clks_service_register(CLKS_SERVICE_KELF, "kelf", (clks_kelf_count() > 0ULL) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED); + clks_service_register(CLKS_SERVICE_USER, + "userland", + (clks_userland_shell_ready() == CLKS_TRUE) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED); clks_log(CLKS_LOG_INFO, "SRV", "KERNEL SERVICES ONLINE"); clks_log_hex(CLKS_LOG_INFO, "SRV", "COUNT", clks_service_count()); diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index bc430d2..6fb9227 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -8,6 +8,7 @@ #include #include #include +#include #define CLKS_SYSCALL_LOG_MAX_LEN 191U #define CLKS_SYSCALL_PATH_MAX 192U @@ -209,6 +210,16 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_exec_request_count(); case CLKS_SYSCALL_EXEC_SUCCESS: return clks_exec_success_count(); + case CLKS_SYSCALL_USER_SHELL_READY: + return (clks_userland_shell_ready() == CLKS_TRUE) ? 1ULL : 0ULL; + case CLKS_SYSCALL_USER_EXEC_REQUESTED: + return (clks_userland_shell_exec_requested() == CLKS_TRUE) ? 1ULL : 0ULL; + case CLKS_SYSCALL_USER_LAUNCH_TRIES: + return clks_userland_launch_attempts(); + case CLKS_SYSCALL_USER_LAUNCH_OK: + return clks_userland_launch_success(); + case CLKS_SYSCALL_USER_LAUNCH_FAIL: + return clks_userland_launch_failures(); default: return (u64)-1; } @@ -225,4 +236,4 @@ u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2) { ); return ret; -} \ No newline at end of file +} diff --git a/clks/kernel/userland.c b/clks/kernel/userland.c index 3741e95..d5df6ca 100644 --- a/clks/kernel/userland.c +++ b/clks/kernel/userland.c @@ -1,9 +1,19 @@ #include +#include #include #include #include #include +#define CLKS_USERLAND_RETRY_INTERVAL 500ULL + +static clks_bool clks_user_shell_ready = CLKS_FALSE; +static clks_bool clks_user_shell_exec_requested_flag = CLKS_FALSE; +static u64 clks_user_launch_attempt_count = 0ULL; +static u64 clks_user_launch_success_count = 0ULL; +static u64 clks_user_launch_fail_count = 0ULL; +static u64 clks_user_last_try_tick = 0ULL; + static clks_bool clks_userland_probe_elf(const char *path, const char *tag) { const void *image; u64 size = 0ULL; @@ -29,13 +39,44 @@ static clks_bool clks_userland_probe_elf(const char *path, const char *tag) { return CLKS_TRUE; } +static clks_bool clks_userland_request_shell_exec(void) { + u64 status = (u64)-1; + + if (clks_user_shell_ready == CLKS_FALSE) { + return CLKS_FALSE; + } + + clks_user_launch_attempt_count++; + + if (clks_exec_run_path("/shell/shell.elf", &status) == CLKS_TRUE && status == 0ULL) { + clks_user_shell_exec_requested_flag = CLKS_TRUE; + clks_user_launch_success_count++; + + clks_log(CLKS_LOG_INFO, "USER", "SHELL EXEC REQUESTED"); + clks_log_hex(CLKS_LOG_INFO, "USER", "SHELL_STATUS", status); + return CLKS_TRUE; + } + + clks_user_launch_fail_count++; + clks_log(CLKS_LOG_WARN, "USER", "SHELL EXEC REQUEST FAILED"); + return CLKS_FALSE; +} + clks_bool clks_userland_init(void) { clks_log(CLKS_LOG_INFO, "USER", "USERLAND FRAMEWORK ONLINE"); + clks_user_shell_ready = CLKS_FALSE; + clks_user_shell_exec_requested_flag = CLKS_FALSE; + clks_user_launch_attempt_count = 0ULL; + clks_user_launch_success_count = 0ULL; + clks_user_launch_fail_count = 0ULL; + clks_user_last_try_tick = 0ULL; + if (clks_userland_probe_elf("/shell/shell.elf", "SHELL ELF READY") == CLKS_FALSE) { return CLKS_FALSE; } + clks_user_shell_ready = CLKS_TRUE; clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY"); if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) { @@ -46,5 +87,39 @@ clks_bool clks_userland_init(void) { return CLKS_FALSE; } + (void)clks_userland_request_shell_exec(); return CLKS_TRUE; -} \ No newline at end of file +} + +void clks_userland_tick(u64 tick) { + if (clks_user_shell_ready == CLKS_FALSE || clks_user_shell_exec_requested_flag == CLKS_TRUE) { + return; + } + + if (tick - clks_user_last_try_tick < CLKS_USERLAND_RETRY_INTERVAL) { + return; + } + + clks_user_last_try_tick = tick; + (void)clks_userland_request_shell_exec(); +} + +clks_bool clks_userland_shell_ready(void) { + return clks_user_shell_ready; +} + +clks_bool clks_userland_shell_exec_requested(void) { + return clks_user_shell_exec_requested_flag; +} + +u64 clks_userland_launch_attempts(void) { + return clks_user_launch_attempt_count; +} + +u64 clks_userland_launch_success(void) { + return clks_user_launch_success_count; +} + +u64 clks_userland_launch_failures(void) { + return clks_user_launch_fail_count; +} diff --git a/docs/stage12.md b/docs/stage12.md new file mode 100644 index 0000000..bf889c2 --- /dev/null +++ b/docs/stage12.md @@ -0,0 +1,45 @@ +# CLeonOS Stage12 + +## Stage Goal +- Add user execution manager in CLKS (`userland manager`) for shell launch lifecycle. +- Connect user execution state to scheduler via a dedicated kernel task (`usrd`). +- Extend syscall ABI with user execution telemetry (`ready/requested/tries/ok/fail`). +- Expose userland status as a first-class kernel service (`CLKS_SERVICE_USER`). + +## Acceptance Criteria +- Kernel boots and prints `CLEONOS STAGE12 START`. +- Userland logs include: + - `USERLAND FRAMEWORK ONLINE` + - `SHELL ELF READY` + - `SHELL EXEC REQUESTED` +- Scheduler task count increases by one (`usrd` added). +- Service framework includes USER service (service count increases). +- Stage12 syscall probe logs include: + - `USER SHELL_READY` + - `USER EXEC_REQUESTED` + - `USER LAUNCH_TRIES` + - `USER LAUNCH_OK` + - `USER LAUNCH_FAIL` +- System remains stable in idle loop with periodic task dispatch logs. + +## 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 +- USER syscall counters always 0: + - Check syscall IDs 16..20 match in kernel and user headers. +- Service count did not increase: + - Confirm `CLKS_SERVICE_USER` is registered in `clks_service_init()`. +- `SHELL EXEC REQUEST FAILED`: + - Ensure `/shell/shell.elf` exists in ramdisk and ELF inspect passes. +- `usrd` task missing: + - Verify `clks_scheduler_add_kernel_task_ex("usrd", ...)` in `kmain`. +- Boot regression after Stage12 merge: + - Re-check init order: FS -> userland init -> driver/kelf/exec -> scheduler -> service -> interrupts.