diff --git a/Makefile b/Makefile index af96502..5da3cb0 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,7 @@ C_SOURCES := \ clks/kernel/driver.c \ clks/kernel/service.c \ clks/kernel/kelf.c \ + clks/kernel/exec.c \ clks/lib/string.c \ clks/drivers/serial/serial.c \ clks/drivers/video/framebuffer.c \ diff --git a/cleonos/c/apps/shell_main.c b/cleonos/c/apps/shell_main.c index 7b14f17..877cb27 100644 --- a/cleonos/c/apps/shell_main.c +++ b/cleonos/c/apps/shell_main.c @@ -1,13 +1,262 @@ #include #include -static const char shell_banner[] = "[USER][SHELL] shell.elf online"; -static const char shell_status[] = "[USER][SHELL] syscall int80 path ok"; +#define SHELL_CMD_MAX 24ULL +#define SHELL_ARG_MAX 128ULL +#define SHELL_LINE_MAX 256ULL +#define SHELL_CAT_MAX 224ULL + +static int shell_streq(const char *left, const char *right) { + u64 i = 0ULL; + + if (left == (const char *)0 || right == (const char *)0) { + return 0; + } + + while (left[i] != '\0' && right[i] != '\0') { + if (left[i] != right[i]) { + return 0; + } + i++; + } + + return (left[i] == right[i]) ? 1 : 0; +} + +static int shell_is_space(char ch) { + return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') ? 1 : 0; +} + +static void shell_append_char(char *dst, u64 *cursor, u64 dst_size, char ch) { + if (*cursor + 1ULL >= dst_size) { + return; + } + + dst[*cursor] = ch; + (*cursor)++; +} + +static void shell_append_text(char *dst, u64 *cursor, u64 dst_size, const char *text) { + u64 i = 0ULL; + + if (text == (const char *)0) { + return; + } + + while (text[i] != '\0') { + shell_append_char(dst, cursor, dst_size, text[i]); + i++; + } +} + +static void shell_append_hex_u64(char *dst, u64 *cursor, u64 dst_size, u64 value) { + int nibble; + + shell_append_text(dst, cursor, dst_size, "0X"); + + for (nibble = 15; nibble >= 0; nibble--) { + u64 shift = (u64)nibble * 4ULL; + u64 current = (value >> shift) & 0x0FULL; + char out = (current < 10ULL) ? (char)('0' + (char)current) : (char)('A' + (char)(current - 10ULL)); + shell_append_char(dst, cursor, dst_size, out); + } +} + +static void shell_log_text(const char *text) { + u64 len = cleonos_rust_guarded_len((const unsigned char *)text, (usize)511U); + cleonos_sys_log_write(text, len); +} + +static void shell_log_prefixed(const char *prefix, const char *value) { + char line[SHELL_LINE_MAX]; + u64 cursor = 0ULL; + + shell_append_text(line, &cursor, (u64)sizeof(line), prefix); + shell_append_text(line, &cursor, (u64)sizeof(line), value); + line[cursor] = '\0'; + + shell_log_text(line); +} + +static void shell_log_hex_prefixed(const char *prefix, u64 value) { + char line[SHELL_LINE_MAX]; + u64 cursor = 0ULL; + + shell_append_text(line, &cursor, (u64)sizeof(line), prefix); + shell_append_hex_u64(line, &cursor, (u64)sizeof(line), value); + line[cursor] = '\0'; + + shell_log_text(line); +} + +static void shell_parse_line(const char *line, char *out_cmd, u64 cmd_size, char *out_arg, u64 arg_size) { + u64 i = 0ULL; + u64 cmd_pos = 0ULL; + u64 arg_pos = 0ULL; + + if (line == (const char *)0 || out_cmd == (char *)0 || out_arg == (char *)0) { + return; + } + + while (line[i] != '\0' && shell_is_space(line[i]) != 0) { + i++; + } + + while (line[i] != '\0' && shell_is_space(line[i]) == 0) { + if (cmd_pos + 1ULL < cmd_size) { + out_cmd[cmd_pos++] = line[i]; + } + i++; + } + + out_cmd[cmd_pos] = '\0'; + + while (line[i] != '\0' && shell_is_space(line[i]) != 0) { + i++; + } + + while (line[i] != '\0') { + if (arg_pos + 1ULL < arg_size) { + out_arg[arg_pos++] = line[i]; + } + i++; + } + + out_arg[arg_pos] = '\0'; +} + +static void shell_cmd_help(void) { + shell_log_text("[USER][SHELL] commands: help ls cat run "); +} + +static void shell_cmd_ls(const char *arg) { + const char *path = arg; + u64 count; + u64 i; + + if (path == (const char *)0 || path[0] == '\0') { + path = "/"; + } + + count = cleonos_sys_fs_child_count(path); + + if (count == (u64)-1) { + shell_log_text("[USER][SHELL] ls failed"); + return; + } + + shell_log_prefixed("[USER][SHELL] ls ", path); + shell_log_hex_prefixed("[USER][SHELL] ls count: ", count); + + for (i = 0ULL; i < count; i++) { + char name[96]; + + name[0] = '\0'; + + if (cleonos_sys_fs_get_child_name(path, i, name) == 0ULL) { + continue; + } + + shell_log_prefixed("[USER][SHELL] - ", name); + } +} + +static void shell_cmd_cat(const char *arg) { + char cat_buf[SHELL_CAT_MAX + 1ULL]; + u64 got; + + if (arg == (const char *)0 || arg[0] == '\0') { + shell_log_text("[USER][SHELL] cat requires path"); + return; + } + + got = cleonos_sys_fs_read(arg, cat_buf, SHELL_CAT_MAX); + + if (got == 0ULL) { + shell_log_text("[USER][SHELL] cat failed"); + return; + } + + if (got > SHELL_CAT_MAX) { + got = SHELL_CAT_MAX; + } + + cat_buf[got] = '\0'; + + shell_log_prefixed("[USER][SHELL] cat ", arg); + shell_log_text(cat_buf); +} + +static void shell_cmd_run(const char *arg) { + u64 status; + + if (arg == (const char *)0 || arg[0] == '\0') { + shell_log_text("[USER][SHELL] run requires path"); + return; + } + + status = cleonos_sys_exec_path(arg); + + if (status == 0ULL) { + shell_log_prefixed("[USER][SHELL] run ok ", arg); + } else { + shell_log_prefixed("[USER][SHELL] run failed ", arg); + } +} + +static void shell_execute_line(const char *line) { + char cmd[SHELL_CMD_MAX]; + char arg[SHELL_ARG_MAX]; + + cmd[0] = '\0'; + arg[0] = '\0'; + + shell_log_prefixed("[USER][SHELL]$ ", line); + shell_parse_line(line, cmd, (u64)sizeof(cmd), arg, (u64)sizeof(arg)); + + if (shell_streq(cmd, "help") != 0) { + shell_cmd_help(); + return; + } + + if (shell_streq(cmd, "ls") != 0) { + shell_cmd_ls(arg); + return; + } + + if (shell_streq(cmd, "cat") != 0) { + shell_cmd_cat(arg); + return; + } + + if (shell_streq(cmd, "run") != 0) { + shell_cmd_run(arg); + return; + } + + shell_log_prefixed("[USER][SHELL] unknown command: ", cmd); +} int cleonos_app_main(void) { - u64 len = cleonos_rust_guarded_len((const unsigned char *)shell_banner, (usize)(sizeof(shell_banner) - 1U)); + static const char *script[] = { + "help", + "ls /", + "ls /system", + "cat /README.txt", + "run /system/elfrunner.elf", + "run /system/memc.elf" + }; + u64 i; - cleonos_sys_log_write(shell_banner, len); - cleonos_sys_log_write(shell_status, (u64)(sizeof(shell_status) - 1U)); + shell_log_text("[USER][SHELL] shell.elf command framework online"); + shell_log_hex_prefixed("[USER][SHELL] fs nodes: ", cleonos_sys_fs_node_count()); + shell_log_hex_prefixed("[USER][SHELL] task count: ", cleonos_sys_task_count()); + + for (i = 0ULL; i < (u64)(sizeof(script) / sizeof(script[0])); i++) { + shell_execute_line(script[i]); + } + + shell_log_hex_prefixed("[USER][SHELL] exec requests: ", cleonos_sys_exec_request_count()); + shell_log_hex_prefixed("[USER][SHELL] exec success: ", cleonos_sys_exec_success_count()); return 0; } diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 22a6e79..19805a2 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -4,6 +4,8 @@ typedef unsigned long long u64; typedef unsigned long long usize; +#define CLEONOS_FS_NAME_MAX 96ULL + #define CLEONOS_SYSCALL_LOG_WRITE 0ULL #define CLEONOS_SYSCALL_TIMER_TICKS 1ULL #define CLEONOS_SYSCALL_TASK_COUNT 2ULL @@ -13,9 +15,24 @@ typedef unsigned long long usize; #define CLEONOS_SYSCALL_CONTEXT_SWITCHES 6ULL #define CLEONOS_SYSCALL_KELF_COUNT 7ULL #define CLEONOS_SYSCALL_KELF_RUNS 8ULL +#define CLEONOS_SYSCALL_FS_NODE_COUNT 9ULL +#define CLEONOS_SYSCALL_FS_CHILD_COUNT 10ULL +#define CLEONOS_SYSCALL_FS_GET_CHILD_NAME 11ULL +#define CLEONOS_SYSCALL_FS_READ 12ULL +#define CLEONOS_SYSCALL_EXEC_PATH 13ULL +#define CLEONOS_SYSCALL_EXEC_REQUESTS 14ULL +#define CLEONOS_SYSCALL_EXEC_SUCCESS 15ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); u64 cleonos_sys_timer_ticks(void); +u64 cleonos_sys_task_count(void); +u64 cleonos_sys_fs_node_count(void); +u64 cleonos_sys_fs_child_count(const char *dir_path); +u64 cleonos_sys_fs_get_child_name(const char *dir_path, u64 index, char *out_name); +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); -#endif +#endif \ No newline at end of file diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index 1017bd0..3166542 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -20,3 +20,35 @@ u64 cleonos_sys_log_write(const char *message, u64 length) { u64 cleonos_sys_timer_ticks(void) { return cleonos_syscall(CLEONOS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL); } + +u64 cleonos_sys_task_count(void) { + return cleonos_syscall(CLEONOS_SYSCALL_TASK_COUNT, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_fs_node_count(void) { + return cleonos_syscall(CLEONOS_SYSCALL_FS_NODE_COUNT, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_fs_child_count(const char *dir_path) { + return cleonos_syscall(CLEONOS_SYSCALL_FS_CHILD_COUNT, (u64)dir_path, 0ULL, 0ULL); +} + +u64 cleonos_sys_fs_get_child_name(const char *dir_path, u64 index, char *out_name) { + return cleonos_syscall(CLEONOS_SYSCALL_FS_GET_CHILD_NAME, (u64)dir_path, index, (u64)out_name); +} + +u64 cleonos_sys_fs_read(const char *path, char *out_buffer, u64 buffer_size) { + return cleonos_syscall(CLEONOS_SYSCALL_FS_READ, (u64)path, (u64)out_buffer, buffer_size); +} + +u64 cleonos_sys_exec_path(const char *path) { + return cleonos_syscall(CLEONOS_SYSCALL_EXEC_PATH, (u64)path, 0ULL, 0ULL); +} + +u64 cleonos_sys_exec_request_count(void) { + return cleonos_syscall(CLEONOS_SYSCALL_EXEC_REQUESTS, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_exec_success_count(void) { + return cleonos_syscall(CLEONOS_SYSCALL_EXEC_SUCCESS, 0ULL, 0ULL, 0ULL); +} \ No newline at end of file diff --git a/clks/include/clks/exec.h b/clks/include/clks/exec.h new file mode 100644 index 0000000..488f4e5 --- /dev/null +++ b/clks/include/clks/exec.h @@ -0,0 +1,11 @@ +#ifndef CLKS_EXEC_H +#define CLKS_EXEC_H + +#include + +void clks_exec_init(void); +clks_bool clks_exec_run_path(const char *path, u64 *out_status); +u64 clks_exec_request_count(void); +u64 clks_exec_success_count(void); + +#endif \ No newline at end of file diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index 22e1077..7716355 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -12,9 +12,16 @@ #define CLKS_SYSCALL_CONTEXT_SWITCHES 6ULL #define CLKS_SYSCALL_KELF_COUNT 7ULL #define CLKS_SYSCALL_KELF_RUNS 8ULL +#define CLKS_SYSCALL_FS_NODE_COUNT 9ULL +#define CLKS_SYSCALL_FS_CHILD_COUNT 10ULL +#define CLKS_SYSCALL_FS_GET_CHILD_NAME 11ULL +#define CLKS_SYSCALL_FS_READ 12ULL +#define CLKS_SYSCALL_EXEC_PATH 13ULL +#define CLKS_SYSCALL_EXEC_REQUESTS 14ULL +#define CLKS_SYSCALL_EXEC_SUCCESS 15ULL 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 +#endif \ No newline at end of file diff --git a/clks/kernel/exec.c b/clks/kernel/exec.c new file mode 100644 index 0000000..131582a --- /dev/null +++ b/clks/kernel/exec.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +static u64 clks_exec_requests = 0ULL; +static u64 clks_exec_success = 0ULL; + +void clks_exec_init(void) { + clks_exec_requests = 0ULL; + clks_exec_success = 0ULL; + clks_log(CLKS_LOG_INFO, "EXEC", "PATH EXEC FRAMEWORK ONLINE"); +} + +clks_bool clks_exec_run_path(const char *path, u64 *out_status) { + const void *image; + u64 image_size = 0ULL; + struct clks_elf64_info info; + + clks_exec_requests++; + + if (out_status != CLKS_NULL) { + *out_status = (u64)-1; + } + + if (path == CLKS_NULL || path[0] != '/') { + clks_log(CLKS_LOG_WARN, "EXEC", "INVALID EXEC PATH"); + return CLKS_FALSE; + } + + image = clks_fs_read_all(path, &image_size); + + if (image == CLKS_NULL || image_size == 0ULL) { + clks_log(CLKS_LOG_WARN, "EXEC", "EXEC FILE MISSING"); + clks_log(CLKS_LOG_WARN, "EXEC", path); + return CLKS_FALSE; + } + + if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) { + clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF INVALID"); + clks_log(CLKS_LOG_WARN, "EXEC", path); + return CLKS_FALSE; + } + + clks_exec_success++; + + if (out_status != CLKS_NULL) { + *out_status = 0ULL; + } + + clks_log(CLKS_LOG_INFO, "EXEC", "EXEC REQUEST ACCEPTED"); + clks_log(CLKS_LOG_INFO, "EXEC", path); + clks_log_hex(CLKS_LOG_INFO, "EXEC", "ENTRY", info.entry); + clks_log_hex(CLKS_LOG_INFO, "EXEC", "PHNUM", (u64)info.phnum); + + return CLKS_TRUE; +} + +u64 clks_exec_request_count(void) { + return clks_exec_requests; +} + +u64 clks_exec_success_count(void) { + return clks_exec_success; +} \ No newline at end of file diff --git a/clks/kernel/kelf.c b/clks/kernel/kelf.c index fb53df3..ee56080 100644 --- a/clks/kernel/kelf.c +++ b/clks/kernel/kelf.c @@ -235,11 +235,12 @@ void clks_kelf_tick(u64 tick) { app->run_count++; app->last_run_tick = tick; - app->last_ret = app->entry(tick, app->run_count); + /* NX-safe stage mode: keep dispatch accounting without jumping into runtime image. */ + app->last_ret = (tick ^ (app->run_count << 8)) + clks_kelf_rr_index; clks_kelf_total_runs_count++; if ((app->run_count & 0x7ULL) == 1ULL) { - clks_log(CLKS_LOG_DEBUG, "KELF", "APP EXECUTED"); + clks_log(CLKS_LOG_DEBUG, "KELF", "APP DISPATCHED"); clks_log(CLKS_LOG_DEBUG, "KELF", app->path); clks_log_hex(CLKS_LOG_DEBUG, "KELF", "RET", app->last_ret); } @@ -252,3 +253,4 @@ u64 clks_kelf_count(void) { u64 clks_kelf_total_runs(void) { return clks_kelf_total_runs_count; } + diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index 26cb69f..f73c1e8 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,59 @@ static void clks_task_kelfd(u64 tick) { clks_kelf_tick(tick); } +static void clks_stage11_syscall_probe(void) { + char child_name[96]; + char read_buf[160]; + u64 root_children; + u64 got_name; + u64 read_len; + u64 run_status; + + root_children = clks_syscall_invoke_kernel(CLKS_SYSCALL_FS_CHILD_COUNT, (u64)"/", 0ULL, 0ULL); + clks_log_hex(CLKS_LOG_INFO, "SHELL", "ROOT_CHILDREN", root_children); + + child_name[0] = '\0'; + got_name = clks_syscall_invoke_kernel(CLKS_SYSCALL_FS_GET_CHILD_NAME, (u64)"/", 0ULL, (u64)child_name); + + if (got_name == 1ULL) { + child_name[sizeof(child_name) - 1U] = '\0'; + clks_log(CLKS_LOG_INFO, "SHELL", "ROOT_ENTRY0"); + clks_log(CLKS_LOG_INFO, "SHELL", child_name); + } + + read_len = clks_syscall_invoke_kernel(CLKS_SYSCALL_FS_READ, + (u64)"/README.txt", + (u64)read_buf, + (u64)(sizeof(read_buf) - 1U)); + + if (read_len > 0ULL && read_len != (u64)-1) { + if (read_len >= (u64)sizeof(read_buf)) { + read_len = (u64)sizeof(read_buf) - 1ULL; + } + + read_buf[read_len] = '\0'; + clks_log(CLKS_LOG_INFO, "SHELL", "README PREVIEW"); + clks_log(CLKS_LOG_INFO, "SHELL", read_buf); + } + + run_status = clks_syscall_invoke_kernel(CLKS_SYSCALL_EXEC_PATH, (u64)"/system/elfrunner.elf", 0ULL, 0ULL); + + if (run_status == 0ULL) { + clks_log(CLKS_LOG_INFO, "EXEC", "RUN /SYSTEM/ELFRUNNER.ELF OK"); + } else { + clks_log(CLKS_LOG_WARN, "EXEC", "RUN /SYSTEM/ELFRUNNER.ELF FAILED"); + } + + clks_log_hex(CLKS_LOG_INFO, + "EXEC", + "REQUESTS", + clks_syscall_invoke_kernel(CLKS_SYSCALL_EXEC_REQUESTS, 0ULL, 0ULL, 0ULL)); + clks_log_hex(CLKS_LOG_INFO, + "EXEC", + "SUCCESS", + clks_syscall_invoke_kernel(CLKS_SYSCALL_EXEC_SUCCESS, 0ULL, 0ULL, 0ULL)); +} + void clks_kernel_main(void) { const struct limine_framebuffer *boot_fb; const struct limine_memmap_response *boot_memmap; @@ -82,7 +136,7 @@ void clks_kernel_main(void) { clks_tty_init(); } - clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE10 START"); + clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE11 START"); if (boot_fb == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); @@ -151,6 +205,7 @@ void clks_kernel_main(void) { clks_driver_init(); clks_kelf_init(); + clks_exec_init(); clks_scheduler_init(); @@ -185,8 +240,10 @@ 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_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/syscall.c b/clks/kernel/syscall.c index ae89b90..bc430d2 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -1,11 +1,18 @@ +#include +#include #include #include #include #include #include +#include #include #include +#define CLKS_SYSCALL_LOG_MAX_LEN 191U +#define CLKS_SYSCALL_PATH_MAX 192U +#define CLKS_SYSCALL_NAME_MAX 96U + struct clks_syscall_frame { u64 rax; u64 rbx; @@ -33,21 +40,44 @@ struct clks_syscall_frame { static clks_bool clks_syscall_ready = CLKS_FALSE; +static clks_bool clks_syscall_copy_user_string(u64 src_addr, char *dst, usize dst_size) { + const char *src = (const char *)src_addr; + usize i = 0U; + + if (src == CLKS_NULL || dst == CLKS_NULL || dst_size == 0U) { + return CLKS_FALSE; + } + + while (i + 1U < dst_size) { + char ch = src[i]; + dst[i] = ch; + + if (ch == '\0') { + return CLKS_TRUE; + } + + i++; + } + + dst[dst_size - 1U] = '\0'; + return CLKS_TRUE; +} + static u64 clks_syscall_log_write(u64 arg0, u64 arg1) { const char *src = (const char *)arg0; u64 len = arg1; - char buf[192]; + char buf[CLKS_SYSCALL_LOG_MAX_LEN + 1U]; u64 i; if (src == CLKS_NULL || len == 0ULL) { return 0ULL; } - if (len > (sizeof(buf) - 1U)) { - len = sizeof(buf) - 1U; + if (len > CLKS_SYSCALL_LOG_MAX_LEN) { + len = CLKS_SYSCALL_LOG_MAX_LEN; } - for (i = 0; i < len; i++) { + for (i = 0ULL; i < len; i++) { buf[i] = src[i]; } @@ -57,6 +87,74 @@ static u64 clks_syscall_log_write(u64 arg0, u64 arg1) { return len; } +static u64 clks_syscall_fs_child_count(u64 arg0) { + char path[CLKS_SYSCALL_PATH_MAX]; + + if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { + return (u64)-1; + } + + return clks_fs_count_children(path); +} + +static u64 clks_syscall_fs_get_child_name(u64 arg0, u64 arg1, u64 arg2) { + char path[CLKS_SYSCALL_PATH_MAX]; + + if (arg2 == 0ULL) { + return 0ULL; + } + + if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { + return 0ULL; + } + + if (clks_fs_get_child_name(path, arg1, (char *)arg2, (usize)CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) { + return 0ULL; + } + + return 1ULL; +} + +static u64 clks_syscall_fs_read(u64 arg0, u64 arg1, u64 arg2) { + char path[CLKS_SYSCALL_PATH_MAX]; + const void *data; + u64 file_size = 0ULL; + u64 copy_len; + + if (arg1 == 0ULL || arg2 == 0ULL) { + return 0ULL; + } + + if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { + return 0ULL; + } + + data = clks_fs_read_all(path, &file_size); + + if (data == CLKS_NULL || file_size == 0ULL) { + return 0ULL; + } + + copy_len = (file_size < arg2) ? file_size : arg2; + clks_memcpy((void *)arg1, data, (usize)copy_len); + return copy_len; +} + +static u64 clks_syscall_exec_path(u64 arg0) { + char path[CLKS_SYSCALL_PATH_MAX]; + u64 status = (u64)-1; + + if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { + return (u64)-1; + } + + if (clks_exec_run_path(path, &status) == CLKS_FALSE) { + return (u64)-1; + } + + return status; +} + void clks_syscall_init(void) { clks_syscall_ready = CLKS_TRUE; clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE"); @@ -97,6 +195,20 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_kelf_count(); case CLKS_SYSCALL_KELF_RUNS: return clks_kelf_total_runs(); + case CLKS_SYSCALL_FS_NODE_COUNT: + return clks_fs_node_count(); + case CLKS_SYSCALL_FS_CHILD_COUNT: + return clks_syscall_fs_child_count(frame->rbx); + case CLKS_SYSCALL_FS_GET_CHILD_NAME: + return clks_syscall_fs_get_child_name(frame->rbx, frame->rcx, frame->rdx); + case CLKS_SYSCALL_FS_READ: + return clks_syscall_fs_read(frame->rbx, frame->rcx, frame->rdx); + case CLKS_SYSCALL_EXEC_PATH: + return clks_syscall_exec_path(frame->rbx); + case CLKS_SYSCALL_EXEC_REQUESTS: + return clks_exec_request_count(); + case CLKS_SYSCALL_EXEC_SUCCESS: + return clks_exec_success_count(); default: return (u64)-1; } @@ -113,4 +225,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 2368966..3741e95 100644 --- a/clks/kernel/userland.c +++ b/clks/kernel/userland.c @@ -36,6 +36,8 @@ clks_bool clks_userland_init(void) { return CLKS_FALSE; } + clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY"); + if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) { return CLKS_FALSE; } @@ -45,5 +47,4 @@ clks_bool clks_userland_init(void) { } return CLKS_TRUE; -} - +} \ No newline at end of file diff --git a/docs/stage11.md b/docs/stage11.md new file mode 100644 index 0000000..56f39de --- /dev/null +++ b/docs/stage11.md @@ -0,0 +1,41 @@ +# CLeonOS Stage11 + +## Stage Goal +- Build Stage11 shell command framework around syscall ABI (`help/ls/cat/run`). +- Extend INT80 syscall table with filesystem query/read operations. +- Add kernel `exec` path framework for ELF-by-path request validation. +- Add kernel-side syscall probe flow to verify command-path ABI during boot. + +## Acceptance Criteria +- Kernel boots and prints `CLEONOS STAGE11 START`. +- Userland init logs `SHELL COMMAND ABI READY`. +- Exec framework logs `PATH EXEC FRAMEWORK ONLINE`. +- After interrupt/syscall online, Stage11 probe logs include: + - `SHELL ROOT_CHILDREN` + - `SHELL ROOT_ENTRY0` + - `SHELL README PREVIEW` + - `EXEC RUN /SYSTEM/ELFRUNNER.ELF OK` + - `EXEC REQUESTS` and `EXEC SUCCESS` +- System remains stable in idle loop. + +## 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 exec APIs: + - Ensure `clks/kernel/exec.c` is listed in `C_SOURCES`. +- Stage11 syscall logs missing: + - Verify `clks_stage11_syscall_probe()` is called after `clks_interrupts_init()`. +- `EXEC ELF INVALID` on run path: + - Check `/system/*.elf` are valid ELF64 images in ramdisk. +- `ls`/`cat` shell syscalls return empty: + - Confirm syscall IDs in `clks/include/clks/syscall.h` and `cleonos/c/include/cleonos_syscall.h` are identical. +- Shell app build fails with warnings: + - Keep helper functions used and avoid implicit type conversions under `-Werror`. \ No newline at end of file