#include #include #include #include #include #include #include #include #include #include #include typedef u64 (*clks_exec_entry_fn)(void); #define CLKS_EXEC_RUN_STACK_BYTES (64ULL * 1024ULL) #define CLKS_EXEC_MAX_PROCS 64U #define CLKS_EXEC_MAX_DEPTH 16U #define CLKS_EXEC_PATH_MAX 192U #define CLKS_EXEC_ARG_LINE_MAX 256U #define CLKS_EXEC_ENV_LINE_MAX 512U #define CLKS_EXEC_MAX_ARGS 24U #define CLKS_EXEC_MAX_ENVS 24U #define CLKS_EXEC_ITEM_MAX 128U #define CLKS_EXEC_STATUS_SIGNAL_FLAG (1ULL << 63) #define CLKS_EXEC_DEFAULT_KILL_SIGNAL CLKS_EXEC_SIGNAL_TERM #define CLKS_EXEC_KERNEL_ADDR_BASE 0xFFFF800000000000ULL #define CLKS_EXEC_UNWIND_CTX_BYTES 56ULL enum clks_exec_proc_state { CLKS_EXEC_PROC_UNUSED = 0, CLKS_EXEC_PROC_PENDING = 1, CLKS_EXEC_PROC_RUNNING = 2, CLKS_EXEC_PROC_EXITED = 3, CLKS_EXEC_PROC_STOPPED = 4, }; struct clks_exec_proc_record { clks_bool used; enum clks_exec_proc_state state; u64 pid; u64 ppid; u64 started_tick; u64 exited_tick; u64 run_started_tick; u64 runtime_ticks_accum; u64 exit_status; u32 tty_index; u64 image_mem_bytes; char path[CLKS_EXEC_PATH_MAX]; char argv_line[CLKS_EXEC_ARG_LINE_MAX]; char env_line[CLKS_EXEC_ENV_LINE_MAX]; u32 argc; u32 envc; char argv_items[CLKS_EXEC_MAX_ARGS][CLKS_EXEC_ITEM_MAX]; char env_items[CLKS_EXEC_MAX_ENVS][CLKS_EXEC_ITEM_MAX]; u64 last_signal; u64 last_fault_vector; u64 last_fault_error; u64 last_fault_rip; }; #if defined(CLKS_ARCH_X86_64) extern u64 clks_exec_call_on_stack_x86_64(void *entry_ptr, void *stack_top); extern void clks_exec_abort_to_caller_x86_64(void); #endif static u64 clks_exec_requests = 0ULL; static u64 clks_exec_success = 0ULL; static u32 clks_exec_running_depth = 0U; static clks_bool clks_exec_pending_dispatch_active = CLKS_FALSE; static struct clks_exec_proc_record clks_exec_proc_table[CLKS_EXEC_MAX_PROCS]; static u64 clks_exec_next_pid = 1ULL; static u64 clks_exec_pid_stack[CLKS_EXEC_MAX_DEPTH]; static clks_bool clks_exec_exit_requested_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_exit_status_stack[CLKS_EXEC_MAX_DEPTH]; static clks_bool clks_exec_stop_requested_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_unwind_slot_stack[CLKS_EXEC_MAX_DEPTH]; static clks_bool clks_exec_unwind_slot_valid_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_image_begin_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_image_end_stack[CLKS_EXEC_MAX_DEPTH]; static u32 clks_exec_pid_stack_depth = 0U; static void clks_exec_serial_write_hex64(u64 value) { int nibble; clks_serial_write("0X"); for (nibble = 15; nibble >= 0; nibble--) { u8 current = (u8)((value >> (nibble * 4)) & 0x0FULL); char out = (current < 10U) ? (char)('0' + current) : (char)('A' + (current - 10U)); clks_serial_write_char(out); } } static void clks_exec_log_info_serial(const char *message) { clks_serial_write("[INFO][EXEC] "); if (message != CLKS_NULL) { clks_serial_write(message); } clks_serial_write("\n"); } static void clks_exec_log_hex_serial(const char *label, u64 value) { clks_serial_write("[INFO][EXEC] "); if (label != CLKS_NULL) { clks_serial_write(label); } clks_serial_write(": "); clks_exec_serial_write_hex64(value); clks_serial_write("\n"); } static clks_bool clks_exec_has_prefix(const char *text, const char *prefix) { usize i = 0U; if (text == CLKS_NULL || prefix == CLKS_NULL) { return CLKS_FALSE; } while (prefix[i] != '\0') { if (text[i] != prefix[i]) { return CLKS_FALSE; } i++; } return CLKS_TRUE; } static clks_bool clks_exec_has_suffix(const char *text, const char *suffix) { usize text_len; usize suffix_len; usize i; if (text == CLKS_NULL || suffix == CLKS_NULL) { return CLKS_FALSE; } text_len = clks_strlen(text); suffix_len = clks_strlen(suffix); if (suffix_len > text_len) { return CLKS_FALSE; } for (i = 0U; i < suffix_len; i++) { if (text[text_len - suffix_len + i] != suffix[i]) { return CLKS_FALSE; } } return CLKS_TRUE; } static clks_bool clks_exec_path_is_user_program(const char *path) { if (path == CLKS_NULL || path[0] != '/') { return CLKS_FALSE; } if (clks_exec_has_prefix(path, "/system/") == CLKS_TRUE) { return CLKS_FALSE; } if (clks_exec_has_prefix(path, "/driver/") == CLKS_TRUE) { return CLKS_FALSE; } if (clks_exec_has_prefix(path, "/shell/") == CLKS_TRUE) { return CLKS_TRUE; } return clks_exec_has_suffix(path, ".elf"); } static clks_bool clks_exec_rip_is_current_user_context(u64 rip) { i32 depth_index; u64 image_begin; u64 image_end; if (rip < CLKS_EXEC_KERNEL_ADDR_BASE) { return CLKS_TRUE; } if (clks_exec_pid_stack_depth == 0U) { return CLKS_FALSE; } depth_index = (i32)(clks_exec_pid_stack_depth - 1U); image_begin = clks_exec_image_begin_stack[(u32)depth_index]; image_end = clks_exec_image_end_stack[(u32)depth_index]; if (image_begin == 0ULL || image_end <= image_begin) { return CLKS_FALSE; } return (rip >= image_begin && rip < image_end) ? CLKS_TRUE : CLKS_FALSE; } static void clks_exec_copy_path(char *dst, usize dst_size, const char *src) { usize i = 0U; if (dst == CLKS_NULL || src == CLKS_NULL || dst_size == 0U) { return; } while (src[i] != '\0' && i + 1U < dst_size) { dst[i] = src[i]; i++; } dst[i] = '\0'; } static void clks_exec_copy_line(char *dst, usize dst_size, const char *src) { usize i = 0U; if (dst == CLKS_NULL || dst_size == 0U) { return; } if (src == CLKS_NULL) { dst[0] = '\0'; return; } while (src[i] != '\0' && i + 1U < dst_size) { dst[i] = src[i]; i++; } dst[i] = '\0'; } static void clks_exec_clear_items(char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { u32 i; for (i = 0U; i < max_count; i++) { items[i][0] = '\0'; } } static u32 clks_exec_parse_whitespace_items(const char *line, char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { u32 count = 0U; usize i = 0U; if (line == CLKS_NULL || items == CLKS_NULL || max_count == 0U) { return 0U; } while (line[i] != '\0') { usize p = 0U; while (line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '\n') { i++; } if (line[i] == '\0') { break; } if (count >= max_count) { break; } while (line[i] != '\0' && line[i] != ' ' && line[i] != '\t' && line[i] != '\r' && line[i] != '\n') { if (p + 1U < CLKS_EXEC_ITEM_MAX) { items[count][p++] = line[i]; } i++; } items[count][p] = '\0'; count++; } return count; } static u32 clks_exec_parse_env_items(const char *line, char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) { u32 count = 0U; usize i = 0U; if (line == CLKS_NULL || items == CLKS_NULL || max_count == 0U) { return 0U; } while (line[i] != '\0') { usize p = 0U; usize end_trim = 0U; while (line[i] == ' ' || line[i] == '\t' || line[i] == ';' || line[i] == '\r' || line[i] == '\n') { i++; } if (line[i] == '\0') { break; } if (count >= max_count) { break; } while (line[i] != '\0' && line[i] != ';' && line[i] != '\r' && line[i] != '\n') { if (p + 1U < CLKS_EXEC_ITEM_MAX) { items[count][p++] = line[i]; } i++; } while (p > 0U && (items[count][p - 1U] == ' ' || items[count][p - 1U] == '\t')) { p--; } end_trim = p; items[count][end_trim] = '\0'; if (end_trim > 0U) { count++; } } return count; } static u64 clks_exec_signal_from_vector(u64 vector) { switch (vector) { case 0ULL: case 16ULL: case 19ULL: return 8ULL; case 6ULL: return 4ULL; case 3ULL: return 5ULL; case 14ULL: case 13ULL: case 12ULL: case 11ULL: case 10ULL: case 17ULL: return 11ULL; default: return 6ULL; } } static u64 clks_exec_encode_signal_status(u64 signal, u64 vector, u64 error_code) { return CLKS_EXEC_STATUS_SIGNAL_FLAG | (signal & 0xFFULL) | ((vector & 0xFFULL) << 8) | ((error_code & 0xFFFFULL) << 16); } static i32 clks_exec_proc_find_slot_by_pid(u64 pid) { u32 i; for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { if (clks_exec_proc_table[i].used == CLKS_TRUE && clks_exec_proc_table[i].pid == pid) { return (i32)i; } } return -1; } static i32 clks_exec_proc_alloc_slot(void) { u32 i; for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { if (clks_exec_proc_table[i].used == CLKS_FALSE) { return (i32)i; } } for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { if (clks_exec_proc_table[i].state == CLKS_EXEC_PROC_EXITED) { return (i32)i; } } return -1; } static i32 clks_exec_current_depth_index(void) { if (clks_exec_pid_stack_depth == 0U) { return -1; } return (i32)(clks_exec_pid_stack_depth - 1U); } static u64 clks_exec_alloc_pid(void) { u64 pid = clks_exec_next_pid; clks_exec_next_pid++; if (clks_exec_next_pid == 0ULL) { clks_exec_next_pid = 1ULL; } if (pid == 0ULL) { pid = clks_exec_next_pid; clks_exec_next_pid++; if (clks_exec_next_pid == 0ULL) { clks_exec_next_pid = 1ULL; } } return pid; } static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot, u64 pid, const char *path, const char *argv_line, const char *env_line, enum clks_exec_proc_state state) { struct clks_exec_proc_record *proc; if (slot < 0 || path == CLKS_NULL) { return CLKS_NULL; } proc = &clks_exec_proc_table[(u32)slot]; clks_memset(proc, 0, sizeof(*proc)); proc->used = CLKS_TRUE; proc->state = state; proc->pid = pid; proc->ppid = clks_exec_current_pid(); proc->started_tick = 0ULL; proc->exited_tick = 0ULL; proc->run_started_tick = 0ULL; proc->runtime_ticks_accum = 0ULL; proc->exit_status = (u64)-1; proc->tty_index = clks_tty_active(); proc->image_mem_bytes = 0ULL; clks_exec_copy_path(proc->path, sizeof(proc->path), path); clks_exec_copy_line(proc->argv_line, sizeof(proc->argv_line), argv_line); clks_exec_copy_line(proc->env_line, sizeof(proc->env_line), env_line); clks_exec_clear_items(proc->argv_items, CLKS_EXEC_MAX_ARGS); clks_exec_clear_items(proc->env_items, CLKS_EXEC_MAX_ENVS); proc->argc = 0U; proc->envc = 0U; proc->last_signal = 0ULL; proc->last_fault_vector = 0ULL; proc->last_fault_error = 0ULL; proc->last_fault_rip = 0ULL; if (proc->argc < CLKS_EXEC_MAX_ARGS) { clks_exec_copy_path(proc->argv_items[proc->argc], CLKS_EXEC_ITEM_MAX, path); proc->argc++; } if (proc->argv_line[0] != '\0' && proc->argc < CLKS_EXEC_MAX_ARGS) { proc->argc += clks_exec_parse_whitespace_items(proc->argv_line, &proc->argv_items[proc->argc], (u32)(CLKS_EXEC_MAX_ARGS - proc->argc)); } if (proc->env_line[0] != '\0') { proc->envc = clks_exec_parse_env_items(proc->env_line, proc->env_items, CLKS_EXEC_MAX_ENVS); } return proc; } static void clks_exec_proc_mark_running(struct clks_exec_proc_record *proc, u64 now_tick) { if (proc == CLKS_NULL) { return; } if (proc->started_tick == 0ULL) { proc->started_tick = now_tick; } proc->run_started_tick = now_tick; proc->state = CLKS_EXEC_PROC_RUNNING; } static void clks_exec_proc_pause_runtime(struct clks_exec_proc_record *proc, u64 now_tick) { if (proc == CLKS_NULL) { return; } if (proc->run_started_tick != 0ULL && now_tick > proc->run_started_tick) { proc->runtime_ticks_accum += (now_tick - proc->run_started_tick); } proc->run_started_tick = 0ULL; } static void clks_exec_proc_mark_exited(struct clks_exec_proc_record *proc, u64 now_tick, u64 status) { if (proc == CLKS_NULL) { return; } clks_exec_proc_pause_runtime(proc, now_tick); proc->state = CLKS_EXEC_PROC_EXITED; proc->exit_status = status; proc->exited_tick = now_tick; } #if defined(CLKS_ARCH_X86_64) static u64 clks_exec_read_rflags(void) { u64 flags = 0ULL; __asm__ volatile("pushfq; popq %0" : "=r"(flags) : : "memory"); return flags; } static clks_bool clks_exec_enable_interrupt_window(void) { if ((clks_exec_read_rflags() & (1ULL << 9)) != 0ULL) { return CLKS_FALSE; } __asm__ volatile("sti" : : : "memory"); return CLKS_TRUE; } static void clks_exec_restore_interrupt_window(clks_bool need_disable) { if (need_disable == CLKS_TRUE) { __asm__ volatile("cli" : : : "memory"); } } #endif static clks_bool clks_exec_invoke_entry(void *entry_ptr, u32 depth_index, u64 *out_ret) { if (entry_ptr == CLKS_NULL || out_ret == CLKS_NULL) { return CLKS_FALSE; } #if defined(CLKS_ARCH_X86_64) { void *stack_base = clks_kmalloc((usize)CLKS_EXEC_RUN_STACK_BYTES); void *stack_top; u64 unwind_slot; u64 call_ret = (u64)-1; clks_bool restore_irq_disable = CLKS_FALSE; if (stack_base == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "EXEC", "RUN STACK ALLOC FAILED"); return CLKS_FALSE; } stack_top = (void *)((u8 *)stack_base + (usize)CLKS_EXEC_RUN_STACK_BYTES); unwind_slot = (((u64)stack_top) & ~0xFULL) - CLKS_EXEC_UNWIND_CTX_BYTES; clks_exec_unwind_slot_stack[depth_index] = unwind_slot; clks_exec_unwind_slot_valid_stack[depth_index] = CLKS_TRUE; if (clks_exec_pending_dispatch_active == CLKS_FALSE) { restore_irq_disable = clks_exec_enable_interrupt_window(); } call_ret = clks_exec_call_on_stack_x86_64(entry_ptr, stack_top); /* Close unwind window immediately after call returns to avoid IRQ race. */ clks_exec_unwind_slot_valid_stack[depth_index] = CLKS_FALSE; clks_exec_unwind_slot_stack[depth_index] = 0ULL; clks_exec_restore_interrupt_window(restore_irq_disable); *out_ret = call_ret; clks_kfree(stack_base); return CLKS_TRUE; } #else (void)depth_index; *out_ret = ((clks_exec_entry_fn)entry_ptr)(); return CLKS_TRUE; #endif } static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) { struct clks_exec_proc_record *proc; const void *image; u64 image_size = 0ULL; struct clks_elf64_info info; struct clks_elf64_loaded_image loaded; clks_bool loaded_active = CLKS_FALSE; clks_bool depth_pushed = CLKS_FALSE; clks_bool depth_counted = CLKS_FALSE; void *entry_ptr; u64 run_ret = (u64)-1; i32 depth_index; clks_memset(&loaded, 0, sizeof(loaded)); if (out_status != CLKS_NULL) { *out_status = (u64)-1; } if (slot < 0 || (u32)slot >= CLKS_EXEC_MAX_PROCS) { return CLKS_FALSE; } proc = &clks_exec_proc_table[(u32)slot]; if (proc->used == CLKS_FALSE) { return CLKS_FALSE; } if (proc->path[0] != '/') { clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); return CLKS_FALSE; } if (clks_exec_pid_stack_depth >= CLKS_EXEC_MAX_DEPTH) { clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS STACK DEPTH EXCEEDED"); clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); return CLKS_FALSE; } clks_exec_proc_mark_running(proc, clks_interrupts_timer_ticks()); depth_index = (i32)clks_exec_pid_stack_depth; clks_exec_pid_stack[(u32)depth_index] = proc->pid; clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_FALSE; clks_exec_exit_status_stack[(u32)depth_index] = 0ULL; clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; clks_exec_image_end_stack[(u32)depth_index] = 0ULL; clks_exec_pid_stack_depth++; depth_pushed = CLKS_TRUE; image = clks_fs_read_all(proc->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", proc->path); goto fail; } 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", proc->path); goto fail; } proc->image_mem_bytes = info.total_load_memsz; if (clks_elf64_load(image, image_size, &loaded) == CLKS_FALSE) { clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF LOAD FAILED"); clks_log(CLKS_LOG_WARN, "EXEC", proc->path); goto fail; } loaded_active = CLKS_TRUE; entry_ptr = clks_elf64_entry_pointer(&loaded, info.entry); if (entry_ptr == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "EXEC", "ENTRY POINTER RESOLVE FAILED"); clks_log(CLKS_LOG_WARN, "EXEC", proc->path); goto fail; } { u64 image_begin = (u64)loaded.image_base; u64 image_end = image_begin + loaded.image_size; if (loaded.image_base == CLKS_NULL || loaded.image_size == 0ULL || image_end <= image_begin) { clks_log(CLKS_LOG_WARN, "EXEC", "EXEC IMAGE WINDOW INVALID"); clks_log(CLKS_LOG_WARN, "EXEC", proc->path); goto fail; } clks_exec_image_begin_stack[(u32)depth_index] = image_begin; clks_exec_image_end_stack[(u32)depth_index] = image_end; } clks_exec_log_info_serial("EXEC RUN START"); clks_exec_log_info_serial(proc->path); clks_exec_log_hex_serial("ENTRY", info.entry); clks_exec_log_hex_serial("PHNUM", (u64)info.phnum); clks_exec_running_depth++; depth_counted = CLKS_TRUE; if (clks_exec_invoke_entry(entry_ptr, (u32)depth_index, &run_ret) == CLKS_FALSE) { clks_log(CLKS_LOG_WARN, "EXEC", "EXEC RUN INVOKE FAILED"); clks_log(CLKS_LOG_WARN, "EXEC", proc->path); goto fail; } if (depth_counted == CLKS_TRUE && clks_exec_running_depth > 0U) { clks_exec_running_depth--; depth_counted = CLKS_FALSE; } if (clks_exec_exit_requested_stack[(u32)depth_index] == CLKS_TRUE) { run_ret = clks_exec_exit_status_stack[(u32)depth_index]; } clks_exec_log_info_serial("RUN RETURNED"); clks_exec_log_info_serial(proc->path); clks_exec_log_hex_serial("RET", run_ret); clks_exec_success++; if (clks_exec_stop_requested_stack[(u32)depth_index] == CLKS_TRUE) { u64 now_tick = clks_interrupts_timer_ticks(); clks_exec_proc_pause_runtime(proc, now_tick); proc->state = CLKS_EXEC_PROC_STOPPED; proc->exit_status = run_ret; proc->exited_tick = 0ULL; clks_exec_log_info_serial("RUN STOPPED"); clks_exec_log_info_serial(proc->path); } else { clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), run_ret); } if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; clks_exec_image_end_stack[(u32)depth_index] = 0ULL; clks_exec_pid_stack_depth--; depth_pushed = CLKS_FALSE; } if (loaded_active == CLKS_TRUE) { clks_elf64_unload(&loaded); } if (out_status != CLKS_NULL) { *out_status = run_ret; } return CLKS_TRUE; fail: if (depth_counted == CLKS_TRUE && clks_exec_running_depth > 0U) { clks_exec_running_depth--; } clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1); if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_FALSE; clks_exec_image_begin_stack[(u32)depth_index] = 0ULL; clks_exec_image_end_stack[(u32)depth_index] = 0ULL; clks_exec_pid_stack_depth--; } if (loaded_active == CLKS_TRUE) { clks_elf64_unload(&loaded); } if (out_status != CLKS_NULL) { *out_status = (u64)-1; } return CLKS_FALSE; } static clks_bool clks_exec_dispatch_pending_once(void) { u32 i; if (clks_exec_pending_dispatch_active == CLKS_TRUE) { return CLKS_FALSE; } for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { if (clks_exec_proc_table[i].used == CLKS_TRUE && clks_exec_proc_table[i].state == CLKS_EXEC_PROC_PENDING) { u64 ignored_status = (u64)-1; clks_exec_pending_dispatch_active = CLKS_TRUE; (void)clks_exec_run_proc_slot((i32)i, &ignored_status); clks_exec_pending_dispatch_active = CLKS_FALSE; return CLKS_TRUE; } } return CLKS_FALSE; } static clks_bool clks_exec_run_path_internal(const char *path, const char *argv_line, const char *env_line, u64 *out_status, u64 *out_pid) { i32 slot; u64 pid; struct clks_exec_proc_record *proc; u64 status = (u64)-1; if (out_status != CLKS_NULL) { *out_status = (u64)-1; } if (out_pid != CLKS_NULL) { *out_pid = (u64)-1; } clks_exec_requests++; if (path == CLKS_NULL || path[0] != '/') { clks_log(CLKS_LOG_WARN, "EXEC", "INVALID EXEC PATH"); return CLKS_FALSE; } slot = clks_exec_proc_alloc_slot(); if (slot < 0) { clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS TABLE FULL"); return CLKS_FALSE; } pid = clks_exec_alloc_pid(); proc = clks_exec_prepare_proc_record(slot, pid, path, argv_line, env_line, CLKS_EXEC_PROC_RUNNING); if (proc == CLKS_NULL) { return CLKS_FALSE; } if (out_pid != CLKS_NULL) { *out_pid = pid; } if (clks_exec_run_proc_slot(slot, &status) == CLKS_FALSE) { return CLKS_FALSE; } if (out_status != CLKS_NULL) { *out_status = status; } return CLKS_TRUE; } void clks_exec_init(void) { clks_exec_requests = 0ULL; clks_exec_success = 0ULL; clks_exec_running_depth = 0U; clks_exec_pending_dispatch_active = CLKS_FALSE; clks_exec_next_pid = 1ULL; clks_exec_pid_stack_depth = 0U; clks_memset(clks_exec_pid_stack, 0, sizeof(clks_exec_pid_stack)); clks_memset(clks_exec_exit_requested_stack, 0, sizeof(clks_exec_exit_requested_stack)); clks_memset(clks_exec_exit_status_stack, 0, sizeof(clks_exec_exit_status_stack)); clks_memset(clks_exec_stop_requested_stack, 0, sizeof(clks_exec_stop_requested_stack)); clks_memset(clks_exec_unwind_slot_stack, 0, sizeof(clks_exec_unwind_slot_stack)); clks_memset(clks_exec_unwind_slot_valid_stack, 0, sizeof(clks_exec_unwind_slot_valid_stack)); clks_memset(clks_exec_image_begin_stack, 0, sizeof(clks_exec_image_begin_stack)); clks_memset(clks_exec_image_end_stack, 0, sizeof(clks_exec_image_end_stack)); clks_memset(clks_exec_proc_table, 0, sizeof(clks_exec_proc_table)); clks_exec_log_info_serial("PATH EXEC FRAMEWORK ONLINE"); } 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); } 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); } clks_bool clks_exec_spawn_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_pid) { i32 slot; u64 pid; struct clks_exec_proc_record *proc; if (out_pid != CLKS_NULL) { *out_pid = (u64)-1; } clks_exec_requests++; if (path == CLKS_NULL || path[0] != '/') { clks_log(CLKS_LOG_WARN, "EXEC", "INVALID SPAWN PATH"); return CLKS_FALSE; } slot = clks_exec_proc_alloc_slot(); if (slot < 0) { clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS TABLE FULL"); return CLKS_FALSE; } pid = clks_exec_alloc_pid(); proc = clks_exec_prepare_proc_record(slot, pid, path, argv_line, env_line, CLKS_EXEC_PROC_PENDING); if (proc == CLKS_NULL) { return CLKS_FALSE; } if (out_pid != CLKS_NULL) { *out_pid = pid; } clks_exec_log_info_serial("SPAWN QUEUED"); clks_exec_log_info_serial(path); clks_exec_log_hex_serial("PID", pid); return CLKS_TRUE; } clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) { return clks_exec_spawn_pathv(path, CLKS_NULL, CLKS_NULL, out_pid); } u64 clks_exec_wait_pid(u64 pid, u64 *out_status) { i32 slot; struct clks_exec_proc_record *proc; slot = clks_exec_proc_find_slot_by_pid(pid); if (slot < 0) { return (u64)-1; } proc = &clks_exec_proc_table[(u32)slot]; if (proc->used == CLKS_FALSE) { return (u64)-1; } if (proc->state == CLKS_EXEC_PROC_PENDING && clks_exec_pending_dispatch_active == CLKS_FALSE) { u64 ignored_status = (u64)-1; clks_exec_pending_dispatch_active = CLKS_TRUE; (void)clks_exec_run_proc_slot(slot, &ignored_status); clks_exec_pending_dispatch_active = CLKS_FALSE; } if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_RUNNING || proc->state == CLKS_EXEC_PROC_STOPPED) { return 0ULL; } if (proc->state != CLKS_EXEC_PROC_EXITED) { return (u64)-1; } if (out_status != CLKS_NULL) { *out_status = proc->exit_status; } return 1ULL; } clks_bool clks_exec_request_exit(u64 status) { i32 depth_index = clks_exec_current_depth_index(); if (depth_index < 0) { return CLKS_FALSE; } clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; clks_exec_exit_status_stack[(u32)depth_index] = status; return CLKS_TRUE; } u64 clks_exec_current_pid(void) { i32 depth_index = clks_exec_current_depth_index(); if (depth_index < 0) { return 0ULL; } return clks_exec_pid_stack[(u32)depth_index]; } u32 clks_exec_current_tty(void) { i32 depth_index = clks_exec_current_depth_index(); u32 tty_count = clks_tty_count(); i32 slot; const struct clks_exec_proc_record *proc; if (tty_count == 0U) { return 0U; } if (depth_index < 0) { u32 active = clks_tty_active(); return (active < tty_count) ? active : 0U; } slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); if (slot < 0) { return 0U; } proc = &clks_exec_proc_table[(u32)slot]; if (proc->used == CLKS_FALSE || proc->tty_index >= tty_count) { return 0U; } return proc->tty_index; } static struct clks_exec_proc_record *clks_exec_current_proc(void) { i32 depth_index = clks_exec_current_depth_index(); i32 slot; if (depth_index < 0) { return CLKS_NULL; } slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); if (slot < 0) { return CLKS_NULL; } if (clks_exec_proc_table[(u32)slot].used == CLKS_FALSE) { return CLKS_NULL; } return &clks_exec_proc_table[(u32)slot]; } u64 clks_exec_current_argc(void) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); if (proc == CLKS_NULL) { return 0ULL; } return (u64)proc->argc; } clks_bool clks_exec_copy_current_argv(u64 index, char *out_value, usize out_size) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); if (proc == CLKS_NULL || out_value == CLKS_NULL || out_size == 0U) { return CLKS_FALSE; } if (index >= (u64)proc->argc || index >= CLKS_EXEC_MAX_ARGS) { return CLKS_FALSE; } clks_exec_copy_line(out_value, out_size, proc->argv_items[(u32)index]); return CLKS_TRUE; } u64 clks_exec_current_envc(void) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); if (proc == CLKS_NULL) { return 0ULL; } return (u64)proc->envc; } clks_bool clks_exec_copy_current_env(u64 index, char *out_value, usize out_size) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); if (proc == CLKS_NULL || out_value == CLKS_NULL || out_size == 0U) { return CLKS_FALSE; } if (index >= (u64)proc->envc || index >= CLKS_EXEC_MAX_ENVS) { return CLKS_FALSE; } clks_exec_copy_line(out_value, out_size, proc->env_items[(u32)index]); return CLKS_TRUE; } u64 clks_exec_current_signal(void) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); return (proc != CLKS_NULL) ? proc->last_signal : 0ULL; } u64 clks_exec_current_fault_vector(void) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); return (proc != CLKS_NULL) ? proc->last_fault_vector : 0ULL; } u64 clks_exec_current_fault_error(void) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); return (proc != CLKS_NULL) ? proc->last_fault_error : 0ULL; } u64 clks_exec_current_fault_rip(void) { const struct clks_exec_proc_record *proc = clks_exec_current_proc(); return (proc != CLKS_NULL) ? proc->last_fault_rip : 0ULL; } static u64 clks_exec_proc_runtime_ticks(const struct clks_exec_proc_record *proc, u64 now_tick) { u64 runtime; if (proc == CLKS_NULL || proc->started_tick == 0ULL) { return 0ULL; } runtime = proc->runtime_ticks_accum; if (proc->state == CLKS_EXEC_PROC_RUNNING && proc->run_started_tick != 0ULL && now_tick > proc->run_started_tick) { runtime += (now_tick - proc->run_started_tick); } return runtime; } static u64 clks_exec_proc_memory_bytes(const struct clks_exec_proc_record *proc) { u64 mem = 0ULL; if (proc == CLKS_NULL) { return 0ULL; } mem += proc->image_mem_bytes; if (proc->state == CLKS_EXEC_PROC_RUNNING) { mem += CLKS_EXEC_RUN_STACK_BYTES; } return mem; } u64 clks_exec_proc_count(void) { u64 count = 0ULL; u32 i; for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { if (clks_exec_proc_table[i].used == CLKS_TRUE) { count++; } } return count; } clks_bool clks_exec_proc_pid_at(u64 index, u64 *out_pid) { u64 pos = 0ULL; u32 i; if (out_pid != CLKS_NULL) { *out_pid = 0ULL; } if (out_pid == CLKS_NULL) { return CLKS_FALSE; } for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { if (clks_exec_proc_table[i].used != CLKS_TRUE) { continue; } if (pos == index) { *out_pid = clks_exec_proc_table[i].pid; return CLKS_TRUE; } pos++; } return CLKS_FALSE; } clks_bool clks_exec_proc_snapshot(u64 pid, struct clks_exec_proc_snapshot *out_snapshot) { i32 slot; const struct clks_exec_proc_record *proc; u64 now_tick; if (out_snapshot == CLKS_NULL) { return CLKS_FALSE; } slot = clks_exec_proc_find_slot_by_pid(pid); if (slot < 0) { return CLKS_FALSE; } proc = &clks_exec_proc_table[(u32)slot]; if (proc->used != CLKS_TRUE) { return CLKS_FALSE; } now_tick = clks_interrupts_timer_ticks(); clks_memset(out_snapshot, 0, sizeof(*out_snapshot)); out_snapshot->pid = proc->pid; out_snapshot->ppid = proc->ppid; out_snapshot->state = (u64)proc->state; out_snapshot->started_tick = proc->started_tick; out_snapshot->exited_tick = proc->exited_tick; out_snapshot->exit_status = proc->exit_status; out_snapshot->runtime_ticks = clks_exec_proc_runtime_ticks(proc, now_tick); out_snapshot->mem_bytes = clks_exec_proc_memory_bytes(proc); out_snapshot->tty_index = (u64)proc->tty_index; out_snapshot->last_signal = proc->last_signal; out_snapshot->last_fault_vector = proc->last_fault_vector; out_snapshot->last_fault_error = proc->last_fault_error; out_snapshot->last_fault_rip = proc->last_fault_rip; clks_exec_copy_path(out_snapshot->path, sizeof(out_snapshot->path), proc->path); return CLKS_TRUE; } u64 clks_exec_proc_kill(u64 pid, u64 signal) { i32 slot; struct clks_exec_proc_record *proc; u64 effective_signal; u64 status; u64 now_tick; if (pid == 0ULL) { return (u64)-1; } slot = clks_exec_proc_find_slot_by_pid(pid); if (slot < 0) { return (u64)-1; } proc = &clks_exec_proc_table[(u32)slot]; if (proc->used != CLKS_TRUE) { return (u64)-1; } effective_signal = (signal == 0ULL) ? CLKS_EXEC_DEFAULT_KILL_SIGNAL : (signal & 0xFFULL); status = clks_exec_encode_signal_status(effective_signal, 0ULL, 0ULL); now_tick = clks_interrupts_timer_ticks(); if (proc->state == CLKS_EXEC_PROC_EXITED) { return 1ULL; } proc->last_signal = effective_signal; proc->last_fault_vector = 0ULL; proc->last_fault_error = 0ULL; proc->last_fault_rip = 0ULL; if (effective_signal == CLKS_EXEC_SIGNAL_CONT) { if (proc->state == CLKS_EXEC_PROC_STOPPED) { proc->state = CLKS_EXEC_PROC_PENDING; } return 1ULL; } if (effective_signal == CLKS_EXEC_SIGNAL_STOP) { if (proc->state == CLKS_EXEC_PROC_PENDING) { proc->state = CLKS_EXEC_PROC_STOPPED; return 1ULL; } if (proc->state == CLKS_EXEC_PROC_STOPPED) { return 1ULL; } } if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_STOPPED) { clks_exec_proc_mark_exited(proc, now_tick, status); return 1ULL; } if (proc->state == CLKS_EXEC_PROC_RUNNING) { i32 depth_index = clks_exec_current_depth_index(); if (depth_index < 0 || clks_exec_current_pid() != pid) { return 0ULL; } if (effective_signal == CLKS_EXEC_SIGNAL_STOP) { clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; clks_exec_exit_status_stack[(u32)depth_index] = status; clks_exec_stop_requested_stack[(u32)depth_index] = CLKS_TRUE; return 1ULL; } clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; clks_exec_exit_status_stack[(u32)depth_index] = status; return 1ULL; } return 0ULL; } u64 clks_exec_force_stop_tty_running_process(u32 tty_index, u64 *out_pid) { u32 tty_count = clks_tty_count(); u64 current_pid; i32 slot; u32 i; if (out_pid != CLKS_NULL) { *out_pid = 0ULL; } if (tty_count == 0U) { tty_count = 1U; } if (tty_index >= tty_count) { tty_index = 0U; } current_pid = clks_exec_current_pid(); if (current_pid != 0ULL) { slot = clks_exec_proc_find_slot_by_pid(current_pid); if (slot >= 0) { const struct clks_exec_proc_record *proc = &clks_exec_proc_table[(u32)slot]; if (proc->used == CLKS_TRUE && proc->state == CLKS_EXEC_PROC_RUNNING && proc->tty_index == tty_index && clks_exec_path_is_user_program(proc->path) == CLKS_TRUE) { u64 ret = clks_exec_proc_kill(current_pid, CLKS_EXEC_SIGNAL_STOP); if (ret == 1ULL && out_pid != CLKS_NULL) { *out_pid = current_pid; } return ret; } } } for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) { u64 ret; if (clks_exec_proc_table[i].used != CLKS_TRUE || clks_exec_proc_table[i].state != CLKS_EXEC_PROC_RUNNING || clks_exec_proc_table[i].tty_index != tty_index || clks_exec_path_is_user_program(clks_exec_proc_table[i].path) == CLKS_FALSE) { continue; } if (out_pid != CLKS_NULL) { *out_pid = clks_exec_proc_table[i].pid; } ret = clks_exec_proc_kill(clks_exec_proc_table[i].pid, CLKS_EXEC_SIGNAL_STOP); if (ret == 1ULL) { return 1ULL; } } return 0ULL; } clks_bool clks_exec_try_unwind_signaled_process(u64 interrupted_rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi) { i32 depth_index; if (io_rip == CLKS_NULL || io_rdi == CLKS_NULL || io_rsi == CLKS_NULL) { return CLKS_FALSE; } if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) { return CLKS_FALSE; } if (clks_exec_rip_is_current_user_context(interrupted_rip) == CLKS_FALSE) { return CLKS_FALSE; } depth_index = clks_exec_current_depth_index(); if (depth_index < 0) { return CLKS_FALSE; } if (clks_exec_stop_requested_stack[(u32)depth_index] == CLKS_FALSE) { return CLKS_FALSE; } #if defined(CLKS_ARCH_X86_64) if (clks_exec_unwind_slot_valid_stack[(u32)depth_index] == CLKS_FALSE) { return CLKS_FALSE; } *io_rip = (u64)clks_exec_abort_to_caller_x86_64; *io_rdi = clks_exec_unwind_slot_stack[(u32)depth_index]; *io_rsi = clks_exec_exit_status_stack[(u32)depth_index]; return CLKS_TRUE; #else (void)depth_index; return CLKS_FALSE; #endif } clks_bool clks_exec_handle_exception(u64 vector, u64 error_code, u64 rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi) { i32 depth_index; struct clks_exec_proc_record *proc; u64 signal; u64 status; if (clks_exec_is_running() == CLKS_FALSE || clks_exec_current_path_is_user() == CLKS_FALSE) { return CLKS_FALSE; } if (clks_exec_rip_is_current_user_context(rip) == CLKS_FALSE) { return CLKS_FALSE; } depth_index = clks_exec_current_depth_index(); proc = clks_exec_current_proc(); if (depth_index < 0 || proc == CLKS_NULL) { return CLKS_FALSE; } signal = clks_exec_signal_from_vector(vector); status = clks_exec_encode_signal_status(signal, vector, error_code); proc->last_signal = signal; proc->last_fault_vector = vector; proc->last_fault_error = error_code; proc->last_fault_rip = rip; clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; clks_exec_exit_status_stack[(u32)depth_index] = status; clks_exec_log_info_serial("USER EXCEPTION CAPTURED"); clks_exec_log_info_serial(proc->path); clks_exec_log_hex_serial("PID", proc->pid); clks_exec_log_hex_serial("SIGNAL", signal); clks_exec_log_hex_serial("VECTOR", vector); clks_exec_log_hex_serial("ERROR", error_code); clks_exec_log_hex_serial("RIP", rip); #if defined(CLKS_ARCH_X86_64) if (io_rip == CLKS_NULL || io_rdi == CLKS_NULL || io_rsi == CLKS_NULL) { return CLKS_FALSE; } if (clks_exec_unwind_slot_valid_stack[(u32)depth_index] == CLKS_FALSE) { return CLKS_FALSE; } *io_rip = (u64)clks_exec_abort_to_caller_x86_64; *io_rdi = clks_exec_unwind_slot_stack[(u32)depth_index]; *io_rsi = status; return CLKS_TRUE; #else (void)io_rip; (void)io_rdi; (void)io_rsi; return CLKS_FALSE; #endif } u64 clks_exec_sleep_ticks(u64 ticks) { u64 start = clks_interrupts_timer_ticks(); if (ticks == 0ULL) { return 0ULL; } while ((clks_interrupts_timer_ticks() - start) < ticks) { #if defined(CLKS_ARCH_X86_64) __asm__ volatile("sti; hlt; cli" : : : "memory"); #elif defined(CLKS_ARCH_AARCH64) clks_cpu_pause(); #endif (void)clks_exec_dispatch_pending_once(); } return clks_interrupts_timer_ticks() - start; } u64 clks_exec_yield(void) { #if defined(CLKS_ARCH_X86_64) __asm__ volatile("sti; hlt; cli" : : : "memory"); #elif defined(CLKS_ARCH_AARCH64) clks_cpu_pause(); #endif (void)clks_exec_dispatch_pending_once(); return clks_interrupts_timer_ticks(); } void clks_exec_tick(u64 tick) { (void)tick; (void)clks_exec_dispatch_pending_once(); } u64 clks_exec_request_count(void) { return clks_exec_requests; } u64 clks_exec_success_count(void) { return clks_exec_success; } clks_bool clks_exec_is_running(void) { return (clks_exec_running_depth > 0U) ? CLKS_TRUE : CLKS_FALSE; } clks_bool clks_exec_current_path_is_user(void) { i32 depth_index; i32 slot; const struct clks_exec_proc_record *proc; depth_index = clks_exec_current_depth_index(); if (depth_index < 0) { return CLKS_FALSE; } slot = clks_exec_proc_find_slot_by_pid(clks_exec_pid_stack[(u32)depth_index]); if (slot < 0) { return CLKS_FALSE; } proc = &clks_exec_proc_table[(u32)slot]; return clks_exec_path_is_user_program(proc->path); }