diff --git a/cleonos/c/apps/shell/shell_cmd.c b/cleonos/c/apps/shell/shell_cmd.c index 81cc6ca..b0eb567 100644 --- a/cleonos/c/apps/shell/shell_cmd.c +++ b/cleonos/c/apps/shell/shell_cmd.c @@ -132,6 +132,7 @@ static int ush_cmd_help(void) { ush_writeln(" wait "); ush_writeln(" sleep "); ush_writeln(" yield"); + ush_writeln(" shutdown / restart"); ush_writeln(" exit [code]"); ush_writeln(" rusttest / panic / elfloader (kernel shell only)"); ush_writeln("edit keys: Left/Right, Home/End, Up/Down history"); @@ -376,6 +377,19 @@ static int ush_cmd_yield(void) { return 1; } + +static int ush_cmd_shutdown(void) { + ush_writeln("shutdown: powering off..."); + (void)cleonos_sys_shutdown(); + return 1; +} + +static int ush_cmd_restart(void) { + ush_writeln("restart: rebooting..."); + (void)cleonos_sys_restart(); + return 1; +} + static int ush_cmd_exit(ush_state *sh, const char *arg) { u64 code = 0ULL; @@ -874,6 +888,10 @@ void ush_execute_line(ush_state *sh, const char *line) { success = ush_cmd_sleep(arg); } else if (ush_streq(cmd, "yield") != 0) { success = ush_cmd_yield(); + } else if (ush_streq(cmd, "shutdown") != 0 || ush_streq(cmd, "poweroff") != 0) { + success = ush_cmd_shutdown(); + } else if (ush_streq(cmd, "restart") != 0 || ush_streq(cmd, "reboot") != 0) { + success = ush_cmd_restart(); } else if (ush_streq(cmd, "exit") != 0) { success = ush_cmd_exit(sh, arg); } else if (ush_streq(cmd, "clear") != 0 || ush_streq(cmd, "cls") != 0) { diff --git a/cleonos/c/include/cleonos_syscall.h b/cleonos/c/include/cleonos_syscall.h index 1258c77..9f361e8 100644 --- a/cleonos/c/include/cleonos_syscall.h +++ b/cleonos/c/include/cleonos_syscall.h @@ -52,6 +52,8 @@ typedef unsigned long long usize; #define CLEONOS_SYSCALL_EXIT 43ULL #define CLEONOS_SYSCALL_SLEEP_TICKS 44ULL #define CLEONOS_SYSCALL_YIELD 45ULL +#define CLEONOS_SYSCALL_SHUTDOWN 46ULL +#define CLEONOS_SYSCALL_RESTART 47ULL u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_sys_log_write(const char *message, u64 length); @@ -99,5 +101,7 @@ u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status); u64 cleonos_sys_exit(u64 status); u64 cleonos_sys_sleep_ticks(u64 ticks); u64 cleonos_sys_yield(void); +u64 cleonos_sys_shutdown(void); +u64 cleonos_sys_restart(void); -#endif \ No newline at end of file +#endif diff --git a/cleonos/c/src/syscall.c b/cleonos/c/src/syscall.c index 686f78d..46966b4 100644 --- a/cleonos/c/src/syscall.c +++ b/cleonos/c/src/syscall.c @@ -191,4 +191,11 @@ u64 cleonos_sys_sleep_ticks(u64 ticks) { u64 cleonos_sys_yield(void) { return cleonos_syscall(CLEONOS_SYSCALL_YIELD, 0ULL, 0ULL, 0ULL); -} \ No newline at end of file +} +u64 cleonos_sys_shutdown(void) { + return cleonos_syscall(CLEONOS_SYSCALL_SHUTDOWN, 0ULL, 0ULL, 0ULL); +} + +u64 cleonos_sys_restart(void) { + return cleonos_syscall(CLEONOS_SYSCALL_RESTART, 0ULL, 0ULL, 0ULL); +} diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h index dde8f91..2e123f0 100644 --- a/clks/include/clks/syscall.h +++ b/clks/include/clks/syscall.h @@ -49,6 +49,8 @@ #define CLKS_SYSCALL_EXIT 43ULL #define CLKS_SYSCALL_SLEEP_TICKS 44ULL #define CLKS_SYSCALL_YIELD 45ULL +#define CLKS_SYSCALL_SHUTDOWN 46ULL +#define CLKS_SYSCALL_RESTART 47ULL void clks_syscall_init(void); u64 clks_syscall_dispatch(void *frame_ptr); diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c index 4bb91d0..92a3143 100644 --- a/clks/kernel/syscall.c +++ b/clks/kernel/syscall.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -51,6 +52,17 @@ 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; +#if defined(CLKS_ARCH_X86_64) +static inline void clks_syscall_outb(u16 port, u8 value) { + __asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port)); +} + +static inline void clks_syscall_outw(u16 port, u16 value) { + __asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port)); +} +#endif + + 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; @@ -247,6 +259,27 @@ static u64 clks_syscall_yield(void) { return clks_exec_yield(); } +static u64 clks_syscall_shutdown(void) { + clks_log(CLKS_LOG_WARN, "SYSCALL", "SHUTDOWN REQUESTED BY USERLAND"); + clks_serial_write("[WARN][SYSCALL] SHUTDOWN REQUESTED\n"); +#if defined(CLKS_ARCH_X86_64) + clks_syscall_outw(0x604U, 0x2000U); +#endif + clks_cpu_halt_forever(); + return 1ULL; +} + +static u64 clks_syscall_restart(void) { + clks_log(CLKS_LOG_WARN, "SYSCALL", "RESTART REQUESTED BY USERLAND"); + clks_serial_write("[WARN][SYSCALL] RESTART REQUESTED\n"); +#if defined(CLKS_ARCH_X86_64) + clks_syscall_outb(0x64U, 0xFEU); +#endif + clks_cpu_halt_forever(); + return 1ULL; +} + + static u64 clks_syscall_fs_stat_type(u64 arg0) { char path[CLKS_SYSCALL_PATH_MAX]; struct clks_fs_node_info info; @@ -545,6 +578,10 @@ u64 clks_syscall_dispatch(void *frame_ptr) { return clks_syscall_sleep_ticks(frame->rbx); case CLKS_SYSCALL_YIELD: return clks_syscall_yield(); + case CLKS_SYSCALL_SHUTDOWN: + return clks_syscall_shutdown(); + case CLKS_SYSCALL_RESTART: + return clks_syscall_restart(); default: return (u64)-1; } diff --git a/docs/syscall.md b/docs/syscall.md index 0383200..3e8ef97 100644 --- a/docs/syscall.md +++ b/docs/syscall.md @@ -52,7 +52,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `FS_MKDIR` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` 仅允许 `/temp` 树下路径。 -## 4. Syscall 列表(0~45) +## 4. Syscall 列表(0~47) ### 0 `CLEONOS_SYSCALL_LOG_WRITE` @@ -209,7 +209,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - 参数:无 - 返回: - 无输入时 `-1` -- 有输入时返回字符值(低 8 位) +- 有输入时返回字符值(低 8 位;按当前进程/TTY 上下文读取) ### 27 `CLEONOS_SYSCALL_FS_STAT_TYPE` @@ -306,7 +306,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - 返回: - 成功:子进程 PID - 失败:`-1` -- 说明:当前 Stage27 为同步 spawn(内部会执行完成后再返回 PID)。 +- 说明:当前实现为异步 spawn(进入 pending 队列,后续由调度 tick 派发执行)。 ### 42 `CLEONOS_SYSCALL_WAITPID` @@ -338,6 +338,18 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - 参数:无 - 返回:当前 tick +### 46 `CLEONOS_SYSCALL_SHUTDOWN` + +- 参数:无 +- 返回:理论上不返回;成功路径会触发关机流程(当前 x86_64 走 QEMU/ACPI 关机端口) +- 说明:若关机流程未生效,内核会进入 halt 循环。 + +### 47 `CLEONOS_SYSCALL_RESTART` + +- 参数:无 +- 返回:理论上不返回;成功路径会触发重启流程(当前 x86_64 走 8042 reset) +- 说明:若重启流程未生效,内核会进入 halt 循环。 + ## 5. 用户态封装函数 用户态封装位于: @@ -353,10 +365,10 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); - `cleonos_sys_tty_write()` - `cleonos_sys_kbd_get_char()` / `cleonos_sys_kbd_buffered()` - `cleonos_sys_getpid()` / `cleonos_sys_spawn_path()` / `cleonos_sys_wait_pid()` -- `cleonos_sys_exit()` / `cleonos_sys_sleep_ticks()` / `cleonos_sys_yield()` +- `cleonos_sys_exit()` / `cleonos_sys_sleep_ticks()` / `cleonos_sys_yield()` / `cleonos_sys_shutdown()` / `cleonos_sys_restart()` ## 6. 开发注意事项 - 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。 - `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`。 -- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。`n \ No newline at end of file +- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。 diff --git a/wine/cleonos_wine_lib/constants.py b/wine/cleonos_wine_lib/constants.py index bf49464..b49f449 100644 --- a/wine/cleonos_wine_lib/constants.py +++ b/wine/cleonos_wine_lib/constants.py @@ -54,6 +54,8 @@ SYS_WAITPID = 42 SYS_EXIT = 43 SYS_SLEEP_TICKS = 44 SYS_YIELD = 45 +SYS_SHUTDOWN = 46 +SYS_RESTART = 47 def u64(value: int) -> int: diff --git a/wine/cleonos_wine_lib/runner.py b/wine/cleonos_wine_lib/runner.py index 87e9c48..9744c01 100644 --- a/wine/cleonos_wine_lib/runner.py +++ b/wine/cleonos_wine_lib/runner.py @@ -25,6 +25,8 @@ from .constants import ( SYS_SPAWN_PATH, SYS_WAITPID, SYS_YIELD, + SYS_SHUTDOWN, + SYS_RESTART, SYS_FS_APPEND, SYS_FS_CHILD_COUNT, SYS_FS_GET_CHILD_NAME, @@ -256,6 +258,16 @@ class CLeonOSWineNative: return self._sleep_ticks(arg0) if sid == SYS_YIELD: return self._yield_once() + if sid == SYS_SHUTDOWN: + self._host_write("\n[WINE] shutdown requested by guest\n") + self._exit_requested = True + self._exit_status = 0 + return 1 + if sid == SYS_RESTART: + self._host_write("\n[WINE] restart requested by guest\n") + self._exit_requested = True + self._exit_status = 0 + return 1 if sid == SYS_EXEC_REQUESTS: return self.state.exec_requests if sid == SYS_EXEC_SUCCESS: @@ -874,4 +886,4 @@ def resolve_elf_target(elf_arg: str, rootfs: Path) -> Tuple[Path, str]: host_path = _guest_to_host_for_resolve(rootfs, guest_path) if host_path is None: raise FileNotFoundError(f"ELF not found as host path or guest path: {elf_arg}") - return host_path.resolve(), guest_path \ No newline at end of file + return host_path.resolve(), guest_path