diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dc497e..b6e940c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,15 @@ cl_set_bool_cache(CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE ON "Run ELFRUNNER kernel E cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KLOGD_TASK ON "Enable scheduler klogd task") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_KWORKER_TASK ON "Enable scheduler kworker task") cl_set_bool_cache(CLEONOS_CLKS_ENABLE_USRD_TASK ON "Enable scheduler usrd task") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG ON "Print boot framebuffer geometry logs") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_PMM_STATS_LOG ON "Print PMM stats logs") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG ON "Print heap stats logs") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_FS_ROOT_LOG ON "Print root children FS log") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK ON "Require /system directory sanity check") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT ON "Initialize ELFRUNNER framework") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY ON "Query syscall timer ticks at boot") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_TTY_READY_LOG ON "Print TTY ready logs") +cl_set_bool_cache(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG ON "Print idle loop debug log") cl_bool_to_int(CLEONOS_CLKS_ENABLE_AUDIO CLKS_CFG_AUDIO_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_MOUSE CLKS_CFG_MOUSE_INT) @@ -167,6 +176,15 @@ cl_bool_to_int(CLEONOS_CLKS_ENABLE_ELFRUNNER_PROBE CLKS_CFG_ELFRUNNER_PROBE_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_KLOGD_TASK CLKS_CFG_KLOGD_TASK_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_KWORKER_TASK CLKS_CFG_KWORKER_TASK_INT) cl_bool_to_int(CLEONOS_CLKS_ENABLE_USRD_TASK CLKS_CFG_USRD_TASK_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG CLKS_CFG_BOOT_VIDEO_LOG_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_PMM_STATS_LOG CLKS_CFG_PMM_STATS_LOG_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG CLKS_CFG_HEAP_STATS_LOG_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_FS_ROOT_LOG CLKS_CFG_FS_ROOT_LOG_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK CLKS_CFG_SYSTEM_DIR_CHECK_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT CLKS_CFG_ELFRUNNER_INIT_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY CLKS_CFG_SYSCALL_TICK_QUERY_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_TTY_READY_LOG CLKS_CFG_TTY_READY_LOG_INT) +cl_bool_to_int(CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG CLKS_CFG_IDLE_DEBUG_LOG_INT) set(CFLAGS_COMMON -std=c11 @@ -195,6 +213,15 @@ set(ARCH_CFLAGS "-DCLKS_CFG_KLOGD_TASK=${CLKS_CFG_KLOGD_TASK_INT}" "-DCLKS_CFG_KWORKER_TASK=${CLKS_CFG_KWORKER_TASK_INT}" "-DCLKS_CFG_USRD_TASK=${CLKS_CFG_USRD_TASK_INT}" + "-DCLKS_CFG_BOOT_VIDEO_LOG=${CLKS_CFG_BOOT_VIDEO_LOG_INT}" + "-DCLKS_CFG_PMM_STATS_LOG=${CLKS_CFG_PMM_STATS_LOG_INT}" + "-DCLKS_CFG_HEAP_STATS_LOG=${CLKS_CFG_HEAP_STATS_LOG_INT}" + "-DCLKS_CFG_FS_ROOT_LOG=${CLKS_CFG_FS_ROOT_LOG_INT}" + "-DCLKS_CFG_SYSTEM_DIR_CHECK=${CLKS_CFG_SYSTEM_DIR_CHECK_INT}" + "-DCLKS_CFG_ELFRUNNER_INIT=${CLKS_CFG_ELFRUNNER_INIT_INT}" + "-DCLKS_CFG_SYSCALL_TICK_QUERY=${CLKS_CFG_SYSCALL_TICK_QUERY_INT}" + "-DCLKS_CFG_TTY_READY_LOG=${CLKS_CFG_TTY_READY_LOG_INT}" + "-DCLKS_CFG_IDLE_DEBUG_LOG=${CLKS_CFG_IDLE_DEBUG_LOG_INT}" -m64 -mno-red-zone -mcmodel=kernel diff --git a/cleonos/c/apps/cat_main.c b/cleonos/c/apps/cat_main.c index b2c685a..a031c94 100644 --- a/cleonos/c/apps/cat_main.c +++ b/cleonos/c/apps/cat_main.c @@ -7,7 +7,7 @@ static int ush_cmd_cat(const ush_state *sh, const char *arg) { u64 fd; if (arg == (const char *)0 || arg[0] == '\0') { - if (ush_pipeline_stdin_text != (const char *)0 && ush_pipeline_stdin_len > 0ULL) { + if (ush_pipeline_stdin_text != (const char *)0) { (void)fputs(ush_pipeline_stdin_text, 1); return 1; } diff --git a/cleonos/c/apps/cmd_runtime.c b/cleonos/c/apps/cmd_runtime.c index f2bca2b..a16c6ab 100644 --- a/cleonos/c/apps/cmd_runtime.c +++ b/cleonos/c/apps/cmd_runtime.c @@ -2,6 +2,87 @@ const char *ush_pipeline_stdin_text = (const char *)0; u64 ush_pipeline_stdin_len = 0ULL; +static char ush_pipeline_stdin_buf[USH_COPY_MAX + 1U]; + +static int ush_cmd_runtime_has_prefix(const char *text, const char *prefix) { + u64 i = 0ULL; + + if (text == (const char *)0 || prefix == (const char *)0) { + return 0; + } + + while (prefix[i] != '\0') { + if (text[i] != prefix[i]) { + return 0; + } + i++; + } + + return 1; +} + +static int ush_cmd_runtime_stdin_pipe_enabled(char **envp) { + u64 i = 0ULL; + + if (envp == (char **)0) { + return 0; + } + + while (envp[i] != (char *)0) { + const char *entry = envp[i]; + + if (ush_cmd_runtime_has_prefix(entry, "USH_STDIN_MODE=PIPE") != 0) { + return 1; + } + + i++; + } + + return 0; +} + +static void ush_cmd_runtime_capture_stdin_pipe(void) { + u64 total = 0ULL; + int truncated = 0; + char drain[256]; + + for (;;) { + u64 got; + + if (total < (u64)USH_COPY_MAX) { + got = cleonos_sys_fd_read(0ULL, ush_pipeline_stdin_buf + total, (u64)USH_COPY_MAX - total); + } else { + got = cleonos_sys_fd_read(0ULL, drain, (u64)sizeof(drain)); + truncated = 1; + } + + if (got == (u64)-1 || got == 0ULL) { + break; + } + + if (total < (u64)USH_COPY_MAX) { + total += got; + } + } + + ush_pipeline_stdin_buf[total] = '\0'; + ush_pipeline_stdin_text = ush_pipeline_stdin_buf; + ush_pipeline_stdin_len = total; + + if (truncated != 0) { + ush_writeln("[pipe] input truncated"); + } +} + +void cleonos_cmd_runtime_pre_main(char **envp) { + ush_pipeline_stdin_text = (const char *)0; + ush_pipeline_stdin_len = 0ULL; + ush_pipeline_stdin_buf[0] = '\0'; + + if (ush_cmd_runtime_stdin_pipe_enabled(envp) != 0) { + ush_cmd_runtime_capture_stdin_pipe(); + } +} void ush_zero(void *ptr, u64 size) { if (ptr == (void *)0 || size == 0ULL) { diff --git a/cleonos/c/apps/shell/shell_cmd.c b/cleonos/c/apps/shell/shell_cmd.c index ed37135..012e794 100644 --- a/cleonos/c/apps/shell/shell_cmd.c +++ b/cleonos/c/apps/shell/shell_cmd.c @@ -2438,6 +2438,23 @@ static int ush_cmd_not_supported(const char *name, const char *why) { return 0; } +static volatile int ush_builtin_fallback_enabled = 0; + +static int ush_builtin_fallback_is_enabled(void) { + return ush_builtin_fallback_enabled; +} + +static void ush_report_external_not_found(const char *cmd) { + ush_write("command not found (external ELF required): "); + + if (cmd == (const char *)0 || cmd[0] == '\0') { + ush_writeln("(empty)"); + return; + } + + ush_writeln(cmd); +} + static int ush_execute_single_command(ush_state *sh, const char *cmd, const char *arg, @@ -2462,13 +2479,31 @@ static int ush_execute_single_command(ush_state *sh, return 0; } - if (allow_external != 0 && ush_try_exec_external(sh, cmd, arg, &success) != 0) { + (void)allow_external; + + if (ush_try_exec_external(sh, cmd, arg, &success) != 0) { if (out_success != (int *)0) { *out_success = success; } return 1; } + if (ush_builtin_fallback_is_enabled() == 0) { + known = 0; + success = 0; + ush_report_external_not_found(cmd); + + if (out_known != (int *)0) { + *out_known = known; + } + + if (out_success != (int *)0) { + *out_success = success; + } + + return 1; + } + if (ush_streq(cmd, "help") != 0) { success = ush_cmd_help(); } else if (ush_streq(cmd, "ls") != 0 || ush_streq(cmd, "dir") != 0) { @@ -2743,6 +2778,23 @@ static int ush_pipeline_open_write_fd(const char *path, u64 flags, u64 *out_fd) return 1; } +static int ush_pipeline_open_read_fd(const char *path, u64 *out_fd) { + u64 fd; + + if (path == (const char *)0 || out_fd == (u64 *)0) { + return 0; + } + + fd = cleonos_sys_fd_open(path, CLEONOS_O_RDONLY, 0ULL); + + if (fd == (u64)-1) { + return 0; + } + + *out_fd = fd; + return 1; +} + static int ush_pipeline_read_path_into_buffer(const char *path, char *buffer, u64 buffer_size, u64 *out_len) { u64 fd; u64 total = 0ULL; @@ -2864,6 +2916,114 @@ static int ush_execute_pipeline(ush_state *sh, return 0; } + if (ush_builtin_fallback_is_enabled() == 0) { + const char *pipe_input_path_external = (const char *)0; + int pipe_output_toggle_external = 0; + + for (i = 0ULL; i < stage_count; i++) { + int stage_known = 1; + int stage_success = 0; + u64 stage_stdin_fd = CLEONOS_FD_INHERIT; + u64 stage_stdout_fd = CLEONOS_FD_INHERIT; + u64 opened_in_fd = (u64)-1; + u64 opened_out_fd = (u64)-1; + const char *stage_pipe_out = (const char *)0; + + if (i + 1ULL < stage_count && stages[i].redirect_mode != 0) { + ush_writeln("pipe: redirection is only supported on final stage"); + known = 1; + success = 0; + break; + } + + if (pipe_input_path_external != (const char *)0) { + if (ush_pipeline_open_read_fd(pipe_input_path_external, &opened_in_fd) == 0) { + ush_writeln("pipe: failed to open stage input"); + success = 0; + break; + } + + stage_stdin_fd = opened_in_fd; + } + + if (i + 1ULL < stage_count) { + stage_pipe_out = (pipe_output_toggle_external == 0) ? USH_PIPE_TMP_A : USH_PIPE_TMP_B; + + if (ush_pipeline_open_write_fd(stage_pipe_out, + CLEONOS_O_WRONLY | CLEONOS_O_CREAT | CLEONOS_O_TRUNC, + &opened_out_fd) == 0) { + ush_writeln("pipe: failed to open temp stream"); + + if (opened_in_fd != (u64)-1) { + (void)cleonos_sys_fd_close(opened_in_fd); + } + + success = 0; + break; + } + + stage_stdout_fd = opened_out_fd; + } else if (stages[i].redirect_mode != 0) { + if (ush_pipeline_open_redirect_fd(sh, &stages[i], &opened_out_fd) == 0) { + if (opened_in_fd != (u64)-1) { + (void)cleonos_sys_fd_close(opened_in_fd); + } + + success = 0; + break; + } + + stage_stdout_fd = opened_out_fd; + } + + stage_known = ush_try_exec_external_with_fds(sh, + stages[i].cmd, + stages[i].arg, + stage_stdin_fd, + stage_stdout_fd, + CLEONOS_FD_INHERIT, + &stage_success); + + if (opened_in_fd != (u64)-1) { + (void)cleonos_sys_fd_close(opened_in_fd); + } + + if (opened_out_fd != (u64)-1) { + (void)cleonos_sys_fd_close(opened_out_fd); + } + + if (stage_known == 0) { + known = 0; + success = 0; + ush_report_external_not_found(stages[i].cmd); + break; + } + + if (stage_success == 0) { + success = 0; + break; + } + + if (i + 1ULL < stage_count) { + pipe_input_path_external = stage_pipe_out; + pipe_output_toggle_external = (pipe_output_toggle_external == 0) ? 1 : 0; + } + } + + (void)cleonos_sys_fs_remove(USH_PIPE_TMP_A); + (void)cleonos_sys_fs_remove(USH_PIPE_TMP_B); + + if (out_known != (int *)0) { + *out_known = known; + } + + if (out_success != (int *)0) { + *out_success = success; + } + + return 1; + } + for (i = 0ULL; i < stage_count; i++) { int stage_known = 1; int stage_success = 0; diff --git a/cleonos/c/apps/shell/shell_external.c b/cleonos/c/apps/shell/shell_external.c index 241f472..51546e6 100644 --- a/cleonos/c/apps/shell/shell_external.c +++ b/cleonos/c/apps/shell/shell_external.c @@ -137,10 +137,16 @@ int ush_command_ret_read(ush_cmd_ret *out_ret) { return (got == (u64)sizeof(*out_ret)) ? 1 : 0; } -int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *out_success) { +int ush_try_exec_external_with_fds(ush_state *sh, + const char *cmd, + const char *arg, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd, + int *out_success) { const char *canonical; char path[USH_PATH_MAX]; - char env_line[USH_PATH_MAX + USH_CMD_MAX + 32ULL]; + char env_line[USH_PATH_MAX + USH_CMD_MAX + 96ULL]; u64 status; ush_cmd_ret ret; @@ -179,7 +185,11 @@ int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int * ush_append_text(env_line, (u64)sizeof(env_line), ";CMD="); ush_append_text(env_line, (u64)sizeof(env_line), canonical); - status = cleonos_sys_exec_pathv(path, arg, env_line); + if (stdin_fd != CLEONOS_FD_INHERIT) { + ush_append_text(env_line, (u64)sizeof(env_line), ";USH_STDIN_MODE=PIPE"); + } + + status = cleonos_sys_exec_pathv_io(path, arg, env_line, stdin_fd, stdout_fd, stderr_fd); if (status == (u64)-1) { ush_writeln("exec: request failed"); @@ -218,3 +228,13 @@ int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int * return 1; } + +int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *out_success) { + return ush_try_exec_external_with_fds(sh, + cmd, + arg, + CLEONOS_FD_INHERIT, + CLEONOS_FD_INHERIT, + CLEONOS_FD_INHERIT, + out_success); +} diff --git a/cleonos/c/apps/shell/shell_internal.h b/cleonos/c/apps/shell/shell_internal.h index d2593ba..4cfd25b 100644 --- a/cleonos/c/apps/shell/shell_internal.h +++ b/cleonos/c/apps/shell/shell_internal.h @@ -112,6 +112,13 @@ void ush_command_ret_reset(void); int ush_command_ret_write(const ush_cmd_ret *ret); int ush_command_ret_read(ush_cmd_ret *out_ret); int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *out_success); +int ush_try_exec_external_with_fds(ush_state *sh, + const char *cmd, + const char *arg, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd, + int *out_success); #endif diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 0adbcb4..fc31c3e 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -24,6 +24,7 @@ typedef unsigned long long usize; #define CLEONOS_O_CREAT 0x0040ULL #define CLEONOS_O_TRUNC 0x0200ULL #define CLEONOS_O_APPEND 0x0400ULL +#define CLEONOS_FD_INHERIT ((u64)-1) typedef struct cleonos_proc_snapshot { u64 pid; @@ -122,6 +123,7 @@ typedef struct cleonos_proc_snapshot { #define CLEONOS_SYSCALL_DL_OPEN 77ULL #define CLEONOS_SYSCALL_DL_CLOSE 78ULL #define CLEONOS_SYSCALL_DL_SYM 79ULL +#define CLEONOS_SYSCALL_EXEC_PATHV_IO 80ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); @@ -138,6 +140,12 @@ u64 cleonos_sys_fs_get_child_name(const char *dir_path, u64 index, char *out_nam 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_pathv(const char *path, const char *argv_line, const char *env_line); +u64 cleonos_sys_exec_pathv_io(const char *path, + const char *argv_line, + const char *env_line, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd); u64 cleonos_sys_exec_request_count(void); u64 cleonos_sys_exec_success_count(void); u64 cleonos_sys_user_shell_ready(void); diff --git a/cleonos/c/src/runtime.c b/cleonos/c/src/runtime.c index 486f52f..a6f9e2c 100644 --- a/cleonos/c/src/runtime.c +++ b/cleonos/c/src/runtime.c @@ -5,6 +5,7 @@ #define CLEONOS_RUNTIME_ITEM_MAX 128ULL extern int cleonos_app_main(int argc, char **argv, char **envp); +extern void cleonos_cmd_runtime_pre_main(char **envp) __attribute__((weak)); u64 _start(void) { static char argv_items[CLEONOS_RUNTIME_ARGV_MAX][CLEONOS_RUNTIME_ITEM_MAX]; @@ -43,6 +44,10 @@ u64 _start(void) { env_ptrs[envc] = (char *)0; + if (cleonos_cmd_runtime_pre_main != (void (*)(char **))0) { + cleonos_cmd_runtime_pre_main(env_ptrs); + } + code = cleonos_app_main((int)argc, argv_ptrs, env_ptrs); return (u64)code; } diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index 12973e4..da8a43c 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -69,6 +69,29 @@ u64 cleonos_sys_exec_pathv(const char *path, const char *argv_line, const char * return cleonos_syscall(CLEONOS_SYSCALL_EXEC_PATHV, (u64)path, (u64)argv_line, (u64)env_line); } +struct cleonos_exec_pathv_io_req { + u64 env_line_ptr; + u64 stdin_fd; + u64 stdout_fd; + u64 stderr_fd; +}; + +u64 cleonos_sys_exec_pathv_io(const char *path, + const char *argv_line, + const char *env_line, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd) { + struct cleonos_exec_pathv_io_req req; + + req.env_line_ptr = (u64)env_line; + req.stdin_fd = stdin_fd; + req.stdout_fd = stdout_fd; + req.stderr_fd = stderr_fd; + + return cleonos_syscall(CLEONOS_SYSCALL_EXEC_PATHV_IO, (u64)path, (u64)argv_line, (u64)&req); +} + u64 cleonos_sys_exec_request_count(void) { return cleonos_syscall(CLEONOS_SYSCALL_EXEC_REQUESTS, 0ULL, 0ULL, 0ULL); } diff --git a/clks/include/clks/exec.h b/clks/include/clks/exec.h index 49973c3..432d3b9 100644 --- a/clks/include/clks/exec.h +++ b/clks/include/clks/exec.h @@ -36,6 +36,13 @@ struct clks_exec_proc_snapshot { void clks_exec_init(void); clks_bool clks_exec_run_path(const char *path, u64 *out_status); clks_bool clks_exec_run_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_status); +clks_bool clks_exec_run_pathv_io(const char *path, + const char *argv_line, + const char *env_line, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd, + u64 *out_status); clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid); clks_bool clks_exec_spawn_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_pid); u64 clks_exec_wait_pid(u64 pid, u64 *out_status); diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index 73e29d6..b18a7d4 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -83,6 +83,7 @@ #define CLKS_SYSCALL_DL_OPEN 77ULL #define CLKS_SYSCALL_DL_CLOSE 78ULL #define CLKS_SYSCALL_DL_SYM 79ULL +#define CLKS_SYSCALL_EXEC_PATHV_IO 80ULL void clks_syscall_init(void); u64 clks_syscall_dispatch(void *frame_ptr); diff --git a/clks/kernel/exec.c b/clks/kernel/exec.c index ec63d59..6c48314 100644 --- a/clks/kernel/exec.c +++ b/clks/kernel/exec.c @@ -34,6 +34,7 @@ typedef u64 (*clks_exec_entry_fn)(void); #define CLKS_EXEC_O_CREAT 0x0040ULL #define CLKS_EXEC_O_TRUNC 0x0200ULL #define CLKS_EXEC_O_APPEND 0x0400ULL +#define CLKS_EXEC_FD_INHERIT ((u64)-1) #define CLKS_EXEC_DYNLIB_MAX 32U #define CLKS_EXEC_ELF64_MAGIC_0 0x7FU @@ -828,6 +829,66 @@ static void clks_exec_fd_init_defaults(struct clks_exec_proc_record *proc) { proc->fds[2].path[0] = '\0'; } +static clks_bool clks_exec_fd_copy_from_parent(struct clks_exec_proc_record *child, + const struct clks_exec_proc_record *parent, + u64 parent_fd, + u64 child_fd, + clks_bool require_read, + clks_bool require_write) { + const struct clks_exec_fd_entry *src; + + if (child == CLKS_NULL || parent == CLKS_NULL || parent_fd >= CLKS_EXEC_FD_MAX || child_fd >= CLKS_EXEC_FD_MAX) { + return CLKS_FALSE; + } + + src = &parent->fds[(u32)parent_fd]; + + if (src->used == CLKS_FALSE) { + return CLKS_FALSE; + } + + if (require_read == CLKS_TRUE && clks_exec_fd_can_read(src->flags) == CLKS_FALSE) { + return CLKS_FALSE; + } + + if (require_write == CLKS_TRUE && clks_exec_fd_can_write(src->flags) == CLKS_FALSE) { + return CLKS_FALSE; + } + + child->fds[(u32)child_fd] = *src; + return CLKS_TRUE; +} + +static clks_bool clks_exec_fd_apply_stdio_overrides(struct clks_exec_proc_record *child, + const struct clks_exec_proc_record *parent, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd) { + if (child == CLKS_NULL) { + return CLKS_FALSE; + } + + if (stdin_fd != CLKS_EXEC_FD_INHERIT) { + if (clks_exec_fd_copy_from_parent(child, parent, stdin_fd, 0ULL, CLKS_TRUE, CLKS_FALSE) == CLKS_FALSE) { + return CLKS_FALSE; + } + } + + if (stdout_fd != CLKS_EXEC_FD_INHERIT) { + if (clks_exec_fd_copy_from_parent(child, parent, stdout_fd, 1ULL, CLKS_FALSE, CLKS_TRUE) == CLKS_FALSE) { + return CLKS_FALSE; + } + } + + if (stderr_fd != CLKS_EXEC_FD_INHERIT) { + if (clks_exec_fd_copy_from_parent(child, parent, stderr_fd, 2ULL, CLKS_FALSE, CLKS_TRUE) == CLKS_FALSE) { + return CLKS_FALSE; + } + } + + return CLKS_TRUE; +} + static i32 clks_exec_fd_find_free(struct clks_exec_proc_record *proc) { u32 i; @@ -1330,10 +1391,14 @@ static clks_bool clks_exec_dispatch_pending_once(void) { static clks_bool clks_exec_run_path_internal(const char *path, const char *argv_line, const char *env_line, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd, u64 *out_status, u64 *out_pid) { i32 slot; u64 pid; + const struct clks_exec_proc_record *parent_proc = clks_exec_current_proc(); struct clks_exec_proc_record *proc; u64 status = (u64)-1; @@ -1366,6 +1431,12 @@ static clks_bool clks_exec_run_path_internal(const char *path, return CLKS_FALSE; } + if (clks_exec_fd_apply_stdio_overrides(proc, parent_proc, stdin_fd, stdout_fd, stderr_fd) == CLKS_FALSE) { + clks_log(CLKS_LOG_WARN, "EXEC", "INVALID STDIO FD OVERRIDE"); + clks_memset(proc, 0, sizeof(*proc)); + return CLKS_FALSE; + } + if (out_pid != CLKS_NULL) { *out_pid = pid; } @@ -1403,11 +1474,35 @@ void clks_exec_init(void) { } clks_bool clks_exec_run_path(const char *path, u64 *out_status) { - return clks_exec_run_path_internal(path, CLKS_NULL, CLKS_NULL, out_status, CLKS_NULL); + return clks_exec_run_path_internal(path, + CLKS_NULL, + CLKS_NULL, + CLKS_EXEC_FD_INHERIT, + CLKS_EXEC_FD_INHERIT, + CLKS_EXEC_FD_INHERIT, + out_status, + CLKS_NULL); } clks_bool clks_exec_run_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_status) { - return clks_exec_run_path_internal(path, argv_line, env_line, out_status, CLKS_NULL); + return clks_exec_run_path_internal(path, + argv_line, + env_line, + CLKS_EXEC_FD_INHERIT, + CLKS_EXEC_FD_INHERIT, + CLKS_EXEC_FD_INHERIT, + out_status, + CLKS_NULL); +} + +clks_bool clks_exec_run_pathv_io(const char *path, + const char *argv_line, + const char *env_line, + u64 stdin_fd, + u64 stdout_fd, + u64 stderr_fd, + u64 *out_status) { + return clks_exec_run_path_internal(path, argv_line, env_line, stdin_fd, stdout_fd, stderr_fd, out_status, CLKS_NULL); } clks_bool clks_exec_spawn_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_pid) { diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index 563b9a4..6e74a13 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -74,6 +74,42 @@ #define CLKS_CFG_USRD_TASK 1 #endif +#ifndef CLKS_CFG_BOOT_VIDEO_LOG +#define CLKS_CFG_BOOT_VIDEO_LOG 1 +#endif + +#ifndef CLKS_CFG_PMM_STATS_LOG +#define CLKS_CFG_PMM_STATS_LOG 1 +#endif + +#ifndef CLKS_CFG_HEAP_STATS_LOG +#define CLKS_CFG_HEAP_STATS_LOG 1 +#endif + +#ifndef CLKS_CFG_FS_ROOT_LOG +#define CLKS_CFG_FS_ROOT_LOG 1 +#endif + +#ifndef CLKS_CFG_SYSTEM_DIR_CHECK +#define CLKS_CFG_SYSTEM_DIR_CHECK 1 +#endif + +#ifndef CLKS_CFG_ELFRUNNER_INIT +#define CLKS_CFG_ELFRUNNER_INIT 1 +#endif + +#ifndef CLKS_CFG_SYSCALL_TICK_QUERY +#define CLKS_CFG_SYSCALL_TICK_QUERY 1 +#endif + +#ifndef CLKS_CFG_TTY_READY_LOG +#define CLKS_CFG_TTY_READY_LOG 1 +#endif + +#ifndef CLKS_CFG_IDLE_DEBUG_LOG +#define CLKS_CFG_IDLE_DEBUG_LOG 1 +#endif + #if CLKS_CFG_KLOGD_TASK static void clks_task_klogd(u64 tick) { static u64 last_emit = 0ULL; @@ -161,10 +197,14 @@ void clks_kernel_main(void) { if (boot_fb == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); } else { +#if CLKS_CFG_BOOT_VIDEO_LOG clks_log_hex(CLKS_LOG_INFO, "VIDEO", "WIDTH", boot_fb->width); clks_log_hex(CLKS_LOG_INFO, "VIDEO", "HEIGHT", boot_fb->height); clks_log_hex(CLKS_LOG_INFO, "VIDEO", "PITCH", boot_fb->pitch); clks_log_hex(CLKS_LOG_INFO, "VIDEO", "BPP", boot_fb->bpp); +#else + clks_log(CLKS_LOG_WARN, "CFG", "BOOT VIDEO LOGS DISABLED BY MENUCONFIG"); +#endif } #if defined(CLKS_ARCH_X86_64) @@ -183,16 +223,26 @@ void clks_kernel_main(void) { clks_pmm_init(boot_memmap); pmm_stats = clks_pmm_get_stats(); +#if CLKS_CFG_PMM_STATS_LOG clks_log_hex(CLKS_LOG_INFO, "PMM", "MANAGED_PAGES", pmm_stats.managed_pages); clks_log_hex(CLKS_LOG_INFO, "PMM", "FREE_PAGES", pmm_stats.free_pages); clks_log_hex(CLKS_LOG_INFO, "PMM", "USED_PAGES", pmm_stats.used_pages); clks_log_hex(CLKS_LOG_INFO, "PMM", "DROPPED_PAGES", pmm_stats.dropped_pages); +#else + (void)pmm_stats; + clks_log(CLKS_LOG_WARN, "CFG", "PMM STATS LOGS DISABLED BY MENUCONFIG"); +#endif clks_heap_init(); heap_stats = clks_heap_get_stats(); +#if CLKS_CFG_HEAP_STATS_LOG clks_log_hex(CLKS_LOG_INFO, "HEAP", "TOTAL_BYTES", heap_stats.total_bytes); clks_log_hex(CLKS_LOG_INFO, "HEAP", "FREE_BYTES", heap_stats.free_bytes); +#else + (void)heap_stats; + clks_log(CLKS_LOG_WARN, "CFG", "HEAP STATS LOGS DISABLED BY MENUCONFIG"); +#endif #if CLKS_CFG_HEAP_SELFTEST void *heap_probe = clks_kmalloc(128); @@ -215,12 +265,21 @@ void clks_kernel_main(void) { } fs_root_children = clks_fs_count_children("/"); +#if CLKS_CFG_FS_ROOT_LOG clks_log_hex(CLKS_LOG_INFO, "FS", "ROOT_CHILDREN", fs_root_children); +#else + (void)fs_root_children; +#endif +#if CLKS_CFG_SYSTEM_DIR_CHECK if (clks_fs_stat("/system", &fs_system_dir) == CLKS_FALSE || fs_system_dir.type != CLKS_FS_NODE_DIR) { clks_log(CLKS_LOG_ERROR, "FS", "/SYSTEM DIRECTORY CHECK FAILED"); clks_cpu_halt_forever(); } +#else + (void)fs_system_dir; + clks_log(CLKS_LOG_WARN, "CFG", "/SYSTEM DIRECTORY CHECK DISABLED BY MENUCONFIG"); +#endif if (boot_fb != CLKS_NULL) { #if CLKS_CFG_EXTERNAL_PSF @@ -318,8 +377,13 @@ void clks_kernel_main(void) { clks_service_init(); +#if CLKS_CFG_ELFRUNNER_INIT clks_elfrunner_init(); +#else + clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER INIT DISABLED BY MENUCONFIG"); +#endif +#if CLKS_CFG_ELFRUNNER_INIT #if CLKS_CFG_ELFRUNNER_PROBE if (clks_elfrunner_probe_kernel_executable() == CLKS_FALSE) { clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF PROBE FAILED"); @@ -327,14 +391,22 @@ void clks_kernel_main(void) { #else clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER PROBE DISABLED BY MENUCONFIG"); #endif +#else + clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER PROBE SKIPPED (INIT DISABLED)"); +#endif clks_syscall_init(); clks_interrupts_init(); clks_log(CLKS_LOG_INFO, "INT", "IDT + PIC INITIALIZED"); +#if CLKS_CFG_SYSCALL_TICK_QUERY syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL); clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks); +#else + (void)syscall_ticks; + clks_log(CLKS_LOG_WARN, "CFG", "SYSCALL TICK QUERY DISABLED BY MENUCONFIG"); +#endif clks_shell_init(); @@ -348,11 +420,15 @@ void clks_kernel_main(void) { clks_log(CLKS_LOG_WARN, "SHELL", "USRD TASK DISABLED; INTERACTIVE SHELL TICK OFF"); #endif +#if CLKS_CFG_TTY_READY_LOG clks_log_hex(CLKS_LOG_INFO, "TTY", "COUNT", (u64)clks_tty_count()); clks_log_hex(CLKS_LOG_INFO, "TTY", "ACTIVE", (u64)clks_tty_active()); clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY"); clks_log(CLKS_LOG_INFO, "TTY", "CURSOR ENABLED"); +#endif +#if CLKS_CFG_IDLE_DEBUG_LOG clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER"); +#endif for (;;) { u64 tick_now = clks_interrupts_timer_ticks(); diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index 0306f35..d29b3b7 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -32,7 +32,7 @@ #define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL) #define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym" #define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL -#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_DL_SYM +#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_EXEC_PATHV_IO #define CLKS_SYSCALL_STATS_RING_SIZE 256U struct clks_syscall_frame { @@ -67,6 +67,13 @@ struct clks_syscall_kdbg_bt_req { u64 out_size; }; +struct clks_syscall_exec_io_req { + u64 env_line_ptr; + u64 stdin_fd; + u64 stdout_fd; + u64 stderr_fd; +}; + static clks_bool clks_syscall_ready = CLKS_FALSE; static clks_bool clks_syscall_user_trace_active = CLKS_FALSE; static u64 clks_syscall_user_trace_budget = 0ULL; @@ -1202,6 +1209,38 @@ static u64 clks_syscall_exec_pathv(u64 arg0, u64 arg1, u64 arg2) { return status; } +static u64 clks_syscall_exec_pathv_io(u64 arg0, u64 arg1, u64 arg2) { + char path[CLKS_SYSCALL_PATH_MAX]; + char argv_line[CLKS_SYSCALL_ARG_LINE_MAX]; + char env_line[CLKS_SYSCALL_ENV_LINE_MAX]; + struct clks_syscall_exec_io_req req; + u64 status = (u64)-1; + + if (arg2 == 0ULL) { + return (u64)-1; + } + + if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { + return (u64)-1; + } + + if (clks_syscall_copy_user_optional_string(arg1, argv_line, sizeof(argv_line)) == CLKS_FALSE) { + return (u64)-1; + } + + clks_memcpy(&req, (const void *)arg2, sizeof(req)); + + if (clks_syscall_copy_user_optional_string(req.env_line_ptr, env_line, sizeof(env_line)) == CLKS_FALSE) { + return (u64)-1; + } + + if (clks_exec_run_pathv_io(path, argv_line, env_line, req.stdin_fd, req.stdout_fd, req.stderr_fd, &status) == CLKS_FALSE) { + return (u64)-1; + } + + return status; +} + static u64 clks_syscall_getpid(void) { return clks_exec_current_pid(); } @@ -1747,6 +1786,8 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_syscall_exec_path(frame->rbx); case CLKS_SYSCALL_EXEC_PATHV: return clks_syscall_exec_pathv(frame->rbx, frame->rcx, frame->rdx); + case CLKS_SYSCALL_EXEC_PATHV_IO: + return clks_syscall_exec_pathv_io(frame->rbx, frame->rcx, frame->rdx); case CLKS_SYSCALL_EXEC_REQUESTS: return clks_exec_request_count(); case CLKS_SYSCALL_EXEC_SUCCESS: diff --git a/configs/menuconfig/clks_features.json b/configs/menuconfig/clks_features.json index ea3cc86..7ff4d63 100644 --- a/configs/menuconfig/clks_features.json +++ b/configs/menuconfig/clks_features.json @@ -77,6 +77,60 @@ "title": "Scheduler Task: usrd", "description": "Enable user/runtime dispatch task (shell tick, tty tick, exec tick).", "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_BOOT_VIDEO_LOG", + "title": "Boot Video Geometry Logs", + "description": "Print framebuffer width/height/pitch/bpp logs at boot.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_PMM_STATS_LOG", + "title": "PMM Stats Logs", + "description": "Print PMM managed/free/used/dropped pages at boot.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_HEAP_STATS_LOG", + "title": "Heap Stats Logs", + "description": "Print heap total/free bytes at boot.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_FS_ROOT_LOG", + "title": "FS Root Children Log", + "description": "Print root directory children count during FS init.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_SYSTEM_DIR_CHECK", + "title": "FS /SYSTEM Sanity Check", + "description": "Require /system directory check during boot.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_ELFRUNNER_INIT", + "title": "ELFRUNNER Init", + "description": "Initialize ELFRUNNER framework in kernel boot path.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_SYSCALL_TICK_QUERY", + "title": "SYSCALL Tick Query", + "description": "Query timer ticks via syscall and log result during boot.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_TTY_READY_LOG", + "title": "TTY Ready Logs", + "description": "Print TTY count/active/cursor ready logs.", + "default": true + }, + { + "key": "CLEONOS_CLKS_ENABLE_IDLE_DEBUG_LOG", + "title": "Idle Loop Debug Log", + "description": "Print debug log before entering kernel idle loop.", + "default": true } ] }