From cb2406cbed2251f1e14bc88f44bc19f3caed6a97 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Fri, 17 Apr 2026 18:09:30 +0800 Subject: [PATCH] Alt+Ctrl+C --- cleonos/c/apps/help_main.c | 1 + cleonos/c/apps/spin_main.c | 16 ++ clks/arch/x86_64/exec_stack_call.S | 20 ++- clks/include/clks/exec.h | 2 + clks/kernel/exec.c | 228 ++++++++++++++++++++++++++++- clks/kernel/interrupts.c | 1 + clks/kernel/keyboard.c | 49 +++++++ 7 files changed, 310 insertions(+), 7 deletions(-) create mode 100644 cleonos/c/apps/spin_main.c diff --git a/cleonos/c/apps/help_main.c b/cleonos/c/apps/help_main.c index 2e2aeb1..a372784 100644 --- a/cleonos/c/apps/help_main.c +++ b/cleonos/c/apps/help_main.c @@ -32,6 +32,7 @@ static int ush_cmd_help(void) { ush_writeln(" kill [signal]"); ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]"); ush_writeln(" sleep "); + ush_writeln(" spin (busy loop test for Alt+Ctrl+C)"); ush_writeln(" yield"); ush_writeln(" shutdown / restart"); ush_writeln(" exit [code]"); diff --git a/cleonos/c/apps/spin_main.c b/cleonos/c/apps/spin_main.c new file mode 100644 index 0000000..dd744a7 --- /dev/null +++ b/cleonos/c/apps/spin_main.c @@ -0,0 +1,16 @@ +#include + +int cleonos_app_main(void) { + static const char banner[] = + "spin: busy loop started (test Alt+Ctrl+C force stop)\n"; + volatile u64 noise = 0xC1E0C1E0ULL; + + (void)cleonos_sys_tty_write(banner, (u64)(sizeof(banner) - 1U)); + + for (;;) { + noise ^= (noise << 7); + noise ^= (noise >> 9); + noise ^= 0x9E3779B97F4A7C15ULL; + noise += 0xA5A5A5A5A5A5A5A5ULL; + } +} diff --git a/clks/arch/x86_64/exec_stack_call.S b/clks/arch/x86_64/exec_stack_call.S index a8b7ea7..b9dd1a8 100644 --- a/clks/arch/x86_64/exec_stack_call.S +++ b/clks/arch/x86_64/exec_stack_call.S @@ -9,11 +9,23 @@ clks_exec_call_on_stack_x86_64: mov r11, rsp mov rsp, rsi and rsp, -16 - sub rsp, 8 + sub rsp, 56 mov [rsp], r11 + mov [rsp + 8], rbx + mov [rsp + 16], rbp + mov [rsp + 24], r12 + mov [rsp + 32], r13 + mov [rsp + 40], r14 + mov [rsp + 48], r15 call rdi + mov rbx, [rsp + 8] + mov rbp, [rsp + 16] + mov r12, [rsp + 24] + mov r13, [rsp + 32] + mov r14, [rsp + 40] + mov r15, [rsp + 48] mov rsp, [rsp] ret @@ -22,6 +34,12 @@ clks_exec_call_on_stack_x86_64: clks_exec_abort_to_caller_x86_64: mov rax, rsi mov rsp, rdi + mov rbx, [rsp + 8] + mov rbp, [rsp + 16] + mov r12, [rsp + 24] + mov r13, [rsp + 32] + mov r14, [rsp + 40] + mov r15, [rsp + 48] mov rsp, [rsp] ret diff --git a/clks/include/clks/exec.h b/clks/include/clks/exec.h index e2d8ead..76f1c75 100644 --- a/clks/include/clks/exec.h +++ b/clks/include/clks/exec.h @@ -54,6 +54,8 @@ u64 clks_exec_proc_count(void); clks_bool clks_exec_proc_pid_at(u64 index, u64 *out_pid); clks_bool clks_exec_proc_snapshot(u64 pid, struct clks_exec_proc_snapshot *out_snapshot); u64 clks_exec_proc_kill(u64 pid, u64 signal); +u64 clks_exec_force_stop_tty_running_process(u32 tty_index, u64 *out_pid); +clks_bool clks_exec_try_unwind_signaled_process(u64 interrupted_rip, u64 *io_rip, u64 *io_rdi, u64 *io_rsi); clks_bool clks_exec_handle_exception(u64 vector, u64 error_code, u64 rip, diff --git a/clks/kernel/exec.c b/clks/kernel/exec.c index 94be5d9..33afe23 100644 --- a/clks/kernel/exec.c +++ b/clks/kernel/exec.c @@ -23,6 +23,8 @@ typedef u64 (*clks_exec_entry_fn)(void); #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, @@ -72,8 +74,11 @@ 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) { @@ -172,6 +177,30 @@ static clks_bool clks_exec_path_is_user_program(const char *path) { 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; @@ -487,6 +516,29 @@ static void clks_exec_proc_mark_exited(struct clks_exec_proc_record *proc, u64 n 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; @@ -497,6 +549,8 @@ static clks_bool clks_exec_invoke_entry(void *entry_ptr, u32 depth_index, u64 *o 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"); @@ -504,12 +558,22 @@ static clks_bool clks_exec_invoke_entry(void *entry_ptr, u32 depth_index, u64 *o } stack_top = (void *)((u8 *)stack_base + (usize)CLKS_EXEC_RUN_STACK_BYTES); - unwind_slot = (((u64)stack_top) & ~0xFULL) - 8ULL; + 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; - *out_ret = clks_exec_call_on_stack_x86_64(entry_ptr, stack_top); + + 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; } @@ -566,6 +630,9 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) { 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; @@ -600,6 +667,20 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) { 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); @@ -628,10 +709,22 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) { clks_exec_log_hex_serial("RET", run_ret); clks_exec_success++; - - clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), run_ret); + 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; } @@ -654,6 +747,9 @@ fail: 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--; } @@ -754,8 +850,11 @@ void clks_exec_init(void) { 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"); } @@ -1166,8 +1265,6 @@ u64 clks_exec_proc_kill(u64 pid, u64 signal) { if (proc->state == CLKS_EXEC_PROC_STOPPED) { return 1ULL; } - - return 0ULL; } if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_STOPPED) { @@ -1182,6 +1279,13 @@ u64 clks_exec_proc_kill(u64 pid, u64 signal) { 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; @@ -1190,6 +1294,114 @@ u64 clks_exec_proc_kill(u64 pid, u64 signal) { 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, @@ -1205,6 +1417,10 @@ clks_bool clks_exec_handle_exception(u64 vector, 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(); diff --git a/clks/kernel/interrupts.c b/clks/kernel/interrupts.c index 5831d7a..7d85bcf 100644 --- a/clks/kernel/interrupts.c +++ b/clks/kernel/interrupts.c @@ -279,6 +279,7 @@ void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) { } if (vector >= CLKS_IRQ_BASE && vector <= CLKS_IRQ_LAST) { + (void)clks_exec_try_unwind_signaled_process(frame->rip, &frame->rip, &frame->rdi, &frame->rsi); clks_pic_send_eoi(vector); } } diff --git a/clks/kernel/keyboard.c b/clks/kernel/keyboard.c index e8a4ec9..ff6e847 100644 --- a/clks/kernel/keyboard.c +++ b/clks/kernel/keyboard.c @@ -13,6 +13,7 @@ #define CLKS_SC_F2 0x3CU #define CLKS_SC_F3 0x3DU #define CLKS_SC_F4 0x3EU +#define CLKS_SC_C 0x2EU #define CLKS_SC_EXT_PREFIX 0xE0U #define CLKS_SC_EXT_HOME 0x47U @@ -62,6 +63,7 @@ static clks_bool clks_kbd_rshift_down = CLKS_FALSE; static clks_bool clks_kbd_lctrl_down = CLKS_FALSE; static clks_bool clks_kbd_rctrl_down = CLKS_FALSE; static clks_bool clks_kbd_e0_prefix = CLKS_FALSE; +static clks_bool clks_kbd_force_stop_latch = CLKS_FALSE; static u64 clks_kbd_hotkey_switches = 0ULL; static u64 clks_kbd_push_count = 0ULL; @@ -202,6 +204,35 @@ static clks_bool clks_keyboard_try_emit_ctrl_shortcut(u8 code, u32 tty_index) { return CLKS_TRUE; } +static clks_bool clks_keyboard_try_force_stop_hotkey(u8 code) { + u64 pid = 0ULL; + u64 stop_ret; + + if (code != CLKS_SC_C) { + return CLKS_FALSE; + } + + if (clks_kbd_alt_down != CLKS_TRUE || clks_keyboard_ctrl_active() == CLKS_FALSE) { + return CLKS_FALSE; + } + + if (clks_kbd_force_stop_latch == CLKS_TRUE) { + return CLKS_TRUE; + } + + clks_kbd_force_stop_latch = CLKS_TRUE; + stop_ret = clks_exec_force_stop_tty_running_process(clks_tty_active(), &pid); + + if (stop_ret == 1ULL) { + clks_log(CLKS_LOG_WARN, "KBD", "HOTKEY CTRL+ALT+C FORCE STOP"); + clks_log_hex(CLKS_LOG_WARN, "KBD", "PID", pid); + } else { + clks_log(CLKS_LOG_WARN, "KBD", "HOTKEY CTRL+ALT+C NO RUNNING USER PROC"); + } + + return CLKS_TRUE; +} + void clks_keyboard_init(void) { u32 tty; @@ -217,6 +248,7 @@ void clks_keyboard_init(void) { clks_kbd_lctrl_down = CLKS_FALSE; clks_kbd_rctrl_down = CLKS_FALSE; clks_kbd_e0_prefix = CLKS_FALSE; + clks_kbd_force_stop_latch = CLKS_FALSE; clks_kbd_hotkey_switches = 0ULL; clks_kbd_push_count = 0ULL; clks_kbd_pop_count = 0ULL; @@ -242,16 +274,25 @@ void clks_keyboard_handle_scancode(u8 scancode) { if (code == CLKS_SC_CTRL) { if (clks_kbd_e0_prefix == CLKS_TRUE) { clks_kbd_rctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; + if (released == CLKS_TRUE) { + clks_kbd_force_stop_latch = CLKS_FALSE; + } clks_kbd_e0_prefix = CLKS_FALSE; return; } clks_kbd_lctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; + if (released == CLKS_TRUE) { + clks_kbd_force_stop_latch = CLKS_FALSE; + } return; } if (code == CLKS_SC_ALT) { clks_kbd_alt_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE; + if (released == CLKS_TRUE) { + clks_kbd_force_stop_latch = CLKS_FALSE; + } if (clks_kbd_e0_prefix == CLKS_TRUE) { clks_kbd_e0_prefix = CLKS_FALSE; @@ -271,6 +312,10 @@ void clks_keyboard_handle_scancode(u8 scancode) { } if (released == CLKS_TRUE) { + if (code == CLKS_SC_C) { + clks_kbd_force_stop_latch = CLKS_FALSE; + } + if (clks_kbd_e0_prefix == CLKS_TRUE) { clks_kbd_e0_prefix = CLKS_FALSE; } @@ -327,6 +372,10 @@ void clks_keyboard_handle_scancode(u8 scancode) { u32 active_tty = clks_tty_active(); char translated; + if (clks_keyboard_try_force_stop_hotkey(code) == CLKS_TRUE) { + return; + } + if (clks_keyboard_try_emit_ctrl_shortcut(code, active_tty) == CLKS_TRUE) { return; }