This commit is contained in:
2026-04-16 22:29:08 +08:00
parent 2d843a100e
commit 589a83cb07
29 changed files with 1397 additions and 49 deletions

View File

@@ -361,7 +361,7 @@ set(RAMDISK_SYSTEM_APPS)
set(RAMDISK_ROOT_APPS) set(RAMDISK_ROOT_APPS)
set(USER_SHELL_COMMAND_APPS set(USER_SHELL_COMMAND_APPS
help ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield
shutdown restart exit clear ansi ansitest wavplay fastfetch memstat fsstat taskstat userstat shutdown restart exit clear ansi ansitest wavplay fastfetch memstat fsstat taskstat userstat
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm
) )

View File

@@ -0,0 +1,61 @@
#include "cmd_runtime.h"
static void ush_args_write_u64_dec(u64 value) {
char tmp[32];
u64 len = 0ULL;
if (value == 0ULL) {
ush_write_char('0');
return;
}
while (value > 0ULL && len < (u64)sizeof(tmp)) {
tmp[len++] = (char)('0' + (value % 10ULL));
value /= 10ULL;
}
while (len > 0ULL) {
len--;
ush_write_char(tmp[len]);
}
}
int cleonos_app_main(int argc, char **argv, char **envp) {
int i;
int env_count = 0;
ush_write("argc=");
ush_args_write_u64_dec((u64)((argc >= 0) ? argc : 0));
ush_write_char('\n');
for (i = 0; i < argc; i++) {
ush_write("argv[");
ush_args_write_u64_dec((u64)i);
ush_write("]=");
if (argv != (char **)0 && argv[i] != (char *)0) {
ush_writeln(argv[i]);
} else {
ush_writeln("(null)");
}
}
if (envp != (char **)0) {
while (envp[env_count] != (char *)0 && env_count < 64) {
env_count++;
}
}
ush_write("envc=");
ush_args_write_u64_dec((u64)env_count);
ush_write_char('\n');
for (i = 0; i < env_count; i++) {
ush_write("env[");
ush_args_write_u64_dec((u64)i);
ush_write("]=");
ush_writeln(envp[i]);
}
return 0;
}

View File

@@ -1,9 +1,28 @@
#include "cmd_runtime.h" #include "cmd_runtime.h"
static int ush_cmd_exec(const ush_state *sh, const char *arg) { static int ush_cmd_exec(const ush_state *sh, const char *arg) {
char target[USH_PATH_MAX];
char argv_line[USH_ARG_MAX];
char env_line[USH_PATH_MAX + 32ULL];
const char *rest = "";
char path[USH_PATH_MAX]; char path[USH_PATH_MAX];
u64 status; u64 status;
if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') {
ush_writeln("exec: usage exec <path|name> [args...]");
return 0;
}
if (ush_split_first_and_rest(arg, target, (u64)sizeof(target), &rest) == 0) {
ush_writeln("exec: usage exec <path|name> [args...]");
return 0;
}
argv_line[0] = '\0';
if (rest != (const char *)0 && rest[0] != '\0') {
ush_copy(argv_line, (u64)sizeof(argv_line), rest);
}
if (ush_resolve_exec_path(sh, target, path, (u64)sizeof(path)) == 0) {
ush_writeln("exec: invalid target"); ush_writeln("exec: invalid target");
return 0; return 0;
} }
@@ -13,7 +32,11 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
return 0; return 0;
} }
status = cleonos_sys_exec_path(path); env_line[0] = '\0';
ush_copy(env_line, (u64)sizeof(env_line), "PWD=");
ush_copy(env_line + 4, (u64)(sizeof(env_line) - 4ULL), sh->cwd);
status = cleonos_sys_exec_pathv(path, argv_line, env_line);
if (status == (u64)-1) { if (status == (u64)-1) {
ush_writeln("exec: request failed"); ush_writeln("exec: request failed");
@@ -25,7 +48,16 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
return 1; return 1;
} }
ush_writeln("exec: returned non-zero status"); if ((status & (1ULL << 63)) != 0ULL) {
ush_writeln("exec: terminated by signal");
ush_print_kv_hex(" SIGNAL", status & 0xFFULL);
ush_print_kv_hex(" VECTOR", (status >> 8) & 0xFFULL);
ush_print_kv_hex(" ERROR", (status >> 16) & 0xFFFFULL);
} else {
ush_writeln("exec: returned non-zero status");
ush_print_kv_hex(" STATUS", status);
}
return 0; return 0;
} }

View File

@@ -2,6 +2,7 @@
static int ush_cmd_help(void) { static int ush_cmd_help(void) {
ush_writeln("commands:"); ush_writeln("commands:");
ush_writeln(" help"); ush_writeln(" help");
ush_writeln(" args [a b c] (print argc/argv/envp)");
ush_writeln(" ls [-l] [-R] [path]"); ush_writeln(" ls [-l] [-R] [path]");
ush_writeln(" cat [file] (reads pipeline input when file omitted)"); ush_writeln(" cat [file] (reads pipeline input when file omitted)");
ush_writeln(" grep [-n] <pattern> [file]"); ush_writeln(" grep [-n] <pattern> [file]");
@@ -9,7 +10,7 @@ static int ush_cmd_help(void) {
ush_writeln(" wc [file] / cut -d <char> -f <N> [file] / uniq [file] / sort [file]"); ush_writeln(" wc [file] / cut -d <char> -f <N> [file] / uniq [file] / sort [file]");
ush_writeln(" pwd"); ush_writeln(" pwd");
ush_writeln(" cd [dir]"); ush_writeln(" cd [dir]");
ush_writeln(" exec|run <path|name>"); ush_writeln(" exec|run <path|name> [args...]");
ush_writeln(" clear"); ush_writeln(" clear");
ush_writeln(" ansi / ansitest / color"); ush_writeln(" ansi / ansitest / color");
ush_writeln(" wavplay <file.wav> [steps] [ticks] / wavplay --stop"); ush_writeln(" wavplay <file.wav> [steps] [ticks] / wavplay --stop");
@@ -26,7 +27,7 @@ static int ush_cmd_help(void) {
ush_writeln(" mv <src> <dst> (/temp only)"); ush_writeln(" mv <src> <dst> (/temp only)");
ush_writeln(" rm <path> (/temp only)"); ush_writeln(" rm <path> (/temp only)");
ush_writeln(" pid"); ush_writeln(" pid");
ush_writeln(" spawn <path|name>"); ush_writeln(" spawn <path|name> [args...]");
ush_writeln(" wait <pid>"); ush_writeln(" wait <pid>");
ush_writeln(" sleep <ticks>"); ush_writeln(" sleep <ticks>");
ush_writeln(" yield"); ush_writeln(" yield");

View File

@@ -127,6 +127,7 @@ static int ush_split_two_args(const char *arg,
static int ush_cmd_help(void) { static int ush_cmd_help(void) {
ush_writeln("commands:"); ush_writeln("commands:");
ush_writeln(" help"); ush_writeln(" help");
ush_writeln(" args [a b c] (print argc/argv/envp)");
ush_writeln(" ls [-l] [-R] [path]"); ush_writeln(" ls [-l] [-R] [path]");
ush_writeln(" cat [file] (reads pipeline input when file omitted)"); ush_writeln(" cat [file] (reads pipeline input when file omitted)");
ush_writeln(" grep [-n] <pattern> [file]"); ush_writeln(" grep [-n] <pattern> [file]");
@@ -134,7 +135,7 @@ static int ush_cmd_help(void) {
ush_writeln(" wc [file] / cut -d <char> -f <N> [file] / uniq [file] / sort [file]"); ush_writeln(" wc [file] / cut -d <char> -f <N> [file] / uniq [file] / sort [file]");
ush_writeln(" pwd"); ush_writeln(" pwd");
ush_writeln(" cd [dir]"); ush_writeln(" cd [dir]");
ush_writeln(" exec|run <path|name>"); ush_writeln(" exec|run <path|name> [args...]");
ush_writeln(" clear"); ush_writeln(" clear");
ush_writeln(" ansi / ansitest / color"); ush_writeln(" ansi / ansitest / color");
ush_writeln(" wavplay <file.wav> [steps] [ticks] / wavplay --stop"); ush_writeln(" wavplay <file.wav> [steps] [ticks] / wavplay --stop");
@@ -151,7 +152,7 @@ static int ush_cmd_help(void) {
ush_writeln(" mv <src> <dst> (/temp only)"); ush_writeln(" mv <src> <dst> (/temp only)");
ush_writeln(" rm <path> (/temp only)"); ush_writeln(" rm <path> (/temp only)");
ush_writeln(" pid"); ush_writeln(" pid");
ush_writeln(" spawn <path|name>"); ush_writeln(" spawn <path|name> [args...]");
ush_writeln(" wait <pid>"); ush_writeln(" wait <pid>");
ush_writeln(" sleep <ticks>"); ush_writeln(" sleep <ticks>");
ush_writeln(" yield"); ush_writeln(" yield");
@@ -1485,10 +1486,29 @@ static int ush_cmd_cd(ush_state *sh, const char *arg) {
} }
static int ush_cmd_exec(const ush_state *sh, const char *arg) { static int ush_cmd_exec(const ush_state *sh, const char *arg) {
char target[USH_PATH_MAX];
char argv_line[USH_ARG_MAX];
char env_line[USH_PATH_MAX + 32ULL];
const char *rest = "";
char path[USH_PATH_MAX]; char path[USH_PATH_MAX];
u64 status; u64 status;
if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') {
ush_writeln("exec: usage exec <path|name> [args...]");
return 0;
}
if (ush_split_first_and_rest(arg, target, (u64)sizeof(target), &rest) == 0) {
ush_writeln("exec: usage exec <path|name> [args...]");
return 0;
}
argv_line[0] = '\0';
if (rest != (const char *)0 && rest[0] != '\0') {
ush_copy(argv_line, (u64)sizeof(argv_line), rest);
}
if (ush_resolve_exec_path(sh, target, path, (u64)sizeof(path)) == 0) {
ush_writeln("exec: invalid target"); ush_writeln("exec: invalid target");
return 0; return 0;
} }
@@ -1498,7 +1518,11 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
return 0; return 0;
} }
status = cleonos_sys_exec_path(path); env_line[0] = '\0';
ush_copy(env_line, (u64)sizeof(env_line), "PWD=");
ush_copy(env_line + 4, (u64)(sizeof(env_line) - 4ULL), sh->cwd);
status = cleonos_sys_exec_pathv(path, argv_line, env_line);
if (status == (u64)-1) { if (status == (u64)-1) {
ush_writeln("exec: request failed"); ush_writeln("exec: request failed");
@@ -1510,7 +1534,16 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
return 1; return 1;
} }
ush_writeln("exec: returned non-zero status"); if ((status & (1ULL << 63)) != 0ULL) {
ush_writeln("exec: terminated by signal");
ush_print_kv_hex(" SIGNAL", status & 0xFFULL);
ush_print_kv_hex(" VECTOR", (status >> 8) & 0xFFULL);
ush_print_kv_hex(" ERROR", (status >> 16) & 0xFFFFULL);
} else {
ush_writeln("exec: returned non-zero status");
ush_print_kv_hex(" STATUS", status);
}
return 0; return 0;
} }
@@ -1520,10 +1553,29 @@ static int ush_cmd_pid(void) {
} }
static int ush_cmd_spawn(const ush_state *sh, const char *arg) { static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
char target[USH_PATH_MAX];
char argv_line[USH_ARG_MAX];
char env_line[USH_PATH_MAX + 32ULL];
const char *rest = "";
char path[USH_PATH_MAX]; char path[USH_PATH_MAX];
u64 pid; u64 pid;
if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') {
ush_writeln("spawn: usage spawn <path|name> [args...]");
return 0;
}
if (ush_split_first_and_rest(arg, target, (u64)sizeof(target), &rest) == 0) {
ush_writeln("spawn: usage spawn <path|name> [args...]");
return 0;
}
argv_line[0] = '\0';
if (rest != (const char *)0 && rest[0] != '\0') {
ush_copy(argv_line, (u64)sizeof(argv_line), rest);
}
if (ush_resolve_exec_path(sh, target, path, (u64)sizeof(path)) == 0) {
ush_writeln("spawn: invalid target"); ush_writeln("spawn: invalid target");
return 0; return 0;
} }
@@ -1533,7 +1585,11 @@ static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
return 0; return 0;
} }
pid = cleonos_sys_spawn_path(path); env_line[0] = '\0';
ush_copy(env_line, (u64)sizeof(env_line), "PWD=");
ush_copy(env_line + 4, (u64)(sizeof(env_line) - 4ULL), sh->cwd);
pid = cleonos_sys_spawn_pathv(path, argv_line, env_line);
if (pid == (u64)-1) { if (pid == (u64)-1) {
ush_writeln("spawn: request failed"); ush_writeln("spawn: request failed");
@@ -1573,7 +1629,13 @@ static int ush_cmd_wait(const char *arg) {
} }
ush_writeln("wait: exited"); ush_writeln("wait: exited");
ush_print_kv_hex(" STATUS", status); if ((status & (1ULL << 63)) != 0ULL) {
ush_print_kv_hex(" SIGNAL", status & 0xFFULL);
ush_print_kv_hex(" VECTOR", (status >> 8) & 0xFFULL);
ush_print_kv_hex(" ERROR", (status >> 16) & 0xFFFFULL);
} else {
ush_print_kv_hex(" STATUS", status);
}
return 1; return 1;
} }

View File

@@ -13,6 +13,25 @@ static void ush_zero(void *ptr, u64 size) {
} }
} }
static void ush_append_text(char *dst, u64 dst_size, const char *text) {
u64 p = 0ULL;
u64 i = 0ULL;
if (dst == (char *)0 || dst_size == 0ULL || text == (const char *)0) {
return;
}
while (dst[p] != '\0' && p + 1ULL < dst_size) {
p++;
}
while (text[i] != '\0' && p + 1ULL < dst_size) {
dst[p++] = text[i++];
}
dst[p] = '\0';
}
static const char *ush_alias_command(const char *cmd) { static const char *ush_alias_command(const char *cmd) {
if (cmd == (const char *)0) { if (cmd == (const char *)0) {
return (const char *)0; return (const char *)0;
@@ -121,6 +140,7 @@ 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(ush_state *sh, const char *cmd, const char *arg, int *out_success) {
const char *canonical; const char *canonical;
char path[USH_PATH_MAX]; char path[USH_PATH_MAX];
char env_line[USH_PATH_MAX + USH_CMD_MAX + 32ULL];
u64 status; u64 status;
ush_cmd_ret ret; ush_cmd_ret ret;
@@ -153,7 +173,13 @@ int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *
return 1; return 1;
} }
status = cleonos_sys_exec_path(path); env_line[0] = '\0';
ush_append_text(env_line, (u64)sizeof(env_line), "PWD=");
ush_append_text(env_line, (u64)sizeof(env_line), sh->cwd);
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 (status == (u64)-1) { if (status == (u64)-1) {
ush_writeln("exec: request failed"); ush_writeln("exec: request failed");
@@ -169,7 +195,15 @@ int ush_try_exec_external(ush_state *sh, const char *cmd, const char *arg, int *
(void)cleonos_sys_fs_remove(USH_CMD_RET_PATH); (void)cleonos_sys_fs_remove(USH_CMD_RET_PATH);
if (status != 0ULL) { if (status != 0ULL) {
ush_writeln("exec: returned non-zero status"); if ((status & (1ULL << 63)) != 0ULL) {
ush_writeln("exec: terminated by signal");
ush_print_kv_hex(" SIGNAL", status & 0xFFULL);
ush_print_kv_hex(" VECTOR", (status >> 8) & 0xFFULL);
ush_print_kv_hex(" ERROR", (status >> 16) & 0xFFFFULL);
} else {
ush_writeln("exec: returned non-zero status");
ush_print_kv_hex(" STATUS", status);
}
if (out_success != (int *)0) { if (out_success != (int *)0) {
*out_success = 0; *out_success = 0;

View File

@@ -1,9 +1,28 @@
#include "cmd_runtime.h" #include "cmd_runtime.h"
static int ush_cmd_spawn(const ush_state *sh, const char *arg) { static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
char target[USH_PATH_MAX];
char argv_line[USH_ARG_MAX];
char env_line[USH_PATH_MAX + 32ULL];
const char *rest = "";
char path[USH_PATH_MAX]; char path[USH_PATH_MAX];
u64 pid; u64 pid;
if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) { if (sh == (const ush_state *)0 || arg == (const char *)0 || arg[0] == '\0') {
ush_writeln("spawn: usage spawn <path|name> [args...]");
return 0;
}
if (ush_split_first_and_rest(arg, target, (u64)sizeof(target), &rest) == 0) {
ush_writeln("spawn: usage spawn <path|name> [args...]");
return 0;
}
argv_line[0] = '\0';
if (rest != (const char *)0 && rest[0] != '\0') {
ush_copy(argv_line, (u64)sizeof(argv_line), rest);
}
if (ush_resolve_exec_path(sh, target, path, (u64)sizeof(path)) == 0) {
ush_writeln("spawn: invalid target"); ush_writeln("spawn: invalid target");
return 0; return 0;
} }
@@ -13,7 +32,11 @@ static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
return 0; return 0;
} }
pid = cleonos_sys_spawn_path(path); env_line[0] = '\0';
ush_copy(env_line, (u64)sizeof(env_line), "PWD=");
ush_copy(env_line + 4, (u64)(sizeof(env_line) - 4ULL), sh->cwd);
pid = cleonos_sys_spawn_pathv(path, argv_line, env_line);
if (pid == (u64)-1) { if (pid == (u64)-1) {
ush_writeln("spawn: request failed"); ush_writeln("spawn: request failed");

View File

@@ -27,7 +27,13 @@ static int ush_cmd_wait(const char *arg) {
} }
ush_writeln("wait: exited"); ush_writeln("wait: exited");
ush_print_kv_hex(" STATUS", status); if ((status & (1ULL << 63)) != 0ULL) {
ush_print_kv_hex(" SIGNAL", status & 0xFFULL);
ush_print_kv_hex(" VECTOR", (status >> 8) & 0xFFULL);
ush_print_kv_hex(" ERROR", (status >> 16) & 0xFFFFULL);
} else {
ush_print_kv_hex(" STATUS", status);
}
return 1; return 1;
} }

View File

@@ -57,6 +57,16 @@ typedef unsigned long long usize;
#define CLEONOS_SYSCALL_AUDIO_AVAILABLE 48ULL #define CLEONOS_SYSCALL_AUDIO_AVAILABLE 48ULL
#define CLEONOS_SYSCALL_AUDIO_PLAY_TONE 49ULL #define CLEONOS_SYSCALL_AUDIO_PLAY_TONE 49ULL
#define CLEONOS_SYSCALL_AUDIO_STOP 50ULL #define CLEONOS_SYSCALL_AUDIO_STOP 50ULL
#define CLEONOS_SYSCALL_EXEC_PATHV 51ULL
#define CLEONOS_SYSCALL_SPAWN_PATHV 52ULL
#define CLEONOS_SYSCALL_PROC_ARGC 53ULL
#define CLEONOS_SYSCALL_PROC_ARGV 54ULL
#define CLEONOS_SYSCALL_PROC_ENVC 55ULL
#define CLEONOS_SYSCALL_PROC_ENV 56ULL
#define CLEONOS_SYSCALL_PROC_LAST_SIGNAL 57ULL
#define CLEONOS_SYSCALL_PROC_FAULT_VECTOR 58ULL
#define CLEONOS_SYSCALL_PROC_FAULT_ERROR 59ULL
#define CLEONOS_SYSCALL_PROC_FAULT_RIP 60ULL
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
u64 cleonos_sys_log_write(const char *message, u64 length); u64 cleonos_sys_log_write(const char *message, u64 length);
@@ -72,6 +82,7 @@ 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_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_fs_read(const char *path, char *out_buffer, u64 buffer_size);
u64 cleonos_sys_exec_path(const char *path); 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_request_count(void); u64 cleonos_sys_exec_request_count(void);
u64 cleonos_sys_exec_success_count(void); u64 cleonos_sys_exec_success_count(void);
u64 cleonos_sys_user_shell_ready(void); u64 cleonos_sys_user_shell_ready(void);
@@ -100,6 +111,7 @@ u64 cleonos_sys_kbd_dropped(void);
u64 cleonos_sys_kbd_hotkey_switches(void); u64 cleonos_sys_kbd_hotkey_switches(void);
u64 cleonos_sys_getpid(void); u64 cleonos_sys_getpid(void);
u64 cleonos_sys_spawn_path(const char *path); u64 cleonos_sys_spawn_path(const char *path);
u64 cleonos_sys_spawn_pathv(const char *path, const char *argv_line, const char *env_line);
u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status); u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status);
u64 cleonos_sys_exit(u64 status); u64 cleonos_sys_exit(u64 status);
u64 cleonos_sys_sleep_ticks(u64 ticks); u64 cleonos_sys_sleep_ticks(u64 ticks);
@@ -109,5 +121,13 @@ u64 cleonos_sys_restart(void);
u64 cleonos_sys_audio_available(void); u64 cleonos_sys_audio_available(void);
u64 cleonos_sys_audio_play_tone(u64 hz, u64 ticks); u64 cleonos_sys_audio_play_tone(u64 hz, u64 ticks);
u64 cleonos_sys_audio_stop(void); u64 cleonos_sys_audio_stop(void);
u64 cleonos_sys_proc_argc(void);
u64 cleonos_sys_proc_argv(u64 index, char *out_value, u64 out_size);
u64 cleonos_sys_proc_envc(void);
u64 cleonos_sys_proc_env(u64 index, char *out_value, u64 out_size);
u64 cleonos_sys_proc_last_signal(void);
u64 cleonos_sys_proc_fault_vector(void);
u64 cleonos_sys_proc_fault_error(void);
u64 cleonos_sys_proc_fault_rip(void);
#endif #endif

View File

@@ -1,12 +1,48 @@
#include <cleonos_syscall.h> #include <cleonos_syscall.h>
typedef int (*cleonos_entry_fn)(void); #define CLEONOS_RUNTIME_ARGV_MAX 24ULL
#define CLEONOS_RUNTIME_ENVP_MAX 24ULL
#define CLEONOS_RUNTIME_ITEM_MAX 128ULL
extern int cleonos_app_main(void); extern int cleonos_app_main(int argc, char **argv, char **envp);
u64 _start(void) { u64 _start(void) {
static char argv_items[CLEONOS_RUNTIME_ARGV_MAX][CLEONOS_RUNTIME_ITEM_MAX];
static char env_items[CLEONOS_RUNTIME_ENVP_MAX][CLEONOS_RUNTIME_ITEM_MAX];
static char *argv_ptrs[CLEONOS_RUNTIME_ARGV_MAX + 1ULL];
static char *env_ptrs[CLEONOS_RUNTIME_ENVP_MAX + 1ULL];
u64 argc = 0ULL;
u64 envc = 0ULL;
u64 i;
int code; int code;
code = ((cleonos_entry_fn)cleonos_app_main)(); argc = cleonos_sys_proc_argc();
envc = cleonos_sys_proc_envc();
if (argc > CLEONOS_RUNTIME_ARGV_MAX) {
argc = CLEONOS_RUNTIME_ARGV_MAX;
}
if (envc > CLEONOS_RUNTIME_ENVP_MAX) {
envc = CLEONOS_RUNTIME_ENVP_MAX;
}
for (i = 0ULL; i < argc; i++) {
argv_items[i][0] = '\0';
(void)cleonos_sys_proc_argv(i, argv_items[i], CLEONOS_RUNTIME_ITEM_MAX);
argv_ptrs[i] = argv_items[i];
}
argv_ptrs[argc] = (char *)0;
for (i = 0ULL; i < envc; i++) {
env_items[i][0] = '\0';
(void)cleonos_sys_proc_env(i, env_items[i], CLEONOS_RUNTIME_ITEM_MAX);
env_ptrs[i] = env_items[i];
}
env_ptrs[envc] = (char *)0;
code = cleonos_app_main((int)argc, argv_ptrs, env_ptrs);
return (u64)code; return (u64)code;
} }

View File

@@ -65,6 +65,10 @@ u64 cleonos_sys_exec_path(const char *path) {
return cleonos_syscall(CLEONOS_SYSCALL_EXEC_PATH, (u64)path, 0ULL, 0ULL); return cleonos_syscall(CLEONOS_SYSCALL_EXEC_PATH, (u64)path, 0ULL, 0ULL);
} }
u64 cleonos_sys_exec_pathv(const char *path, const char *argv_line, const char *env_line) {
return cleonos_syscall(CLEONOS_SYSCALL_EXEC_PATHV, (u64)path, (u64)argv_line, (u64)env_line);
}
u64 cleonos_sys_exec_request_count(void) { u64 cleonos_sys_exec_request_count(void) {
return cleonos_syscall(CLEONOS_SYSCALL_EXEC_REQUESTS, 0ULL, 0ULL, 0ULL); return cleonos_syscall(CLEONOS_SYSCALL_EXEC_REQUESTS, 0ULL, 0ULL, 0ULL);
} }
@@ -177,6 +181,10 @@ u64 cleonos_sys_spawn_path(const char *path) {
return cleonos_syscall(CLEONOS_SYSCALL_SPAWN_PATH, (u64)path, 0ULL, 0ULL); return cleonos_syscall(CLEONOS_SYSCALL_SPAWN_PATH, (u64)path, 0ULL, 0ULL);
} }
u64 cleonos_sys_spawn_pathv(const char *path, const char *argv_line, const char *env_line) {
return cleonos_syscall(CLEONOS_SYSCALL_SPAWN_PATHV, (u64)path, (u64)argv_line, (u64)env_line);
}
u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status) { u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status) {
return cleonos_syscall(CLEONOS_SYSCALL_WAITPID, pid, (u64)out_status, 0ULL); return cleonos_syscall(CLEONOS_SYSCALL_WAITPID, pid, (u64)out_status, 0ULL);
} }
@@ -212,3 +220,35 @@ u64 cleonos_sys_audio_play_tone(u64 hz, u64 ticks) {
u64 cleonos_sys_audio_stop(void) { u64 cleonos_sys_audio_stop(void) {
return cleonos_syscall(CLEONOS_SYSCALL_AUDIO_STOP, 0ULL, 0ULL, 0ULL); return cleonos_syscall(CLEONOS_SYSCALL_AUDIO_STOP, 0ULL, 0ULL, 0ULL);
} }
u64 cleonos_sys_proc_argc(void) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_ARGC, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_proc_argv(u64 index, char *out_value, u64 out_size) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_ARGV, index, (u64)out_value, out_size);
}
u64 cleonos_sys_proc_envc(void) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_ENVC, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_proc_env(u64 index, char *out_value, u64 out_size) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_ENV, index, (u64)out_value, out_size);
}
u64 cleonos_sys_proc_last_signal(void) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_LAST_SIGNAL, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_proc_fault_vector(void) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_FAULT_VECTOR, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_proc_fault_error(void) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_FAULT_ERROR, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_proc_fault_rip(void) {
return cleonos_syscall(CLEONOS_SYSCALL_PROC_FAULT_RIP, 0ULL, 0ULL, 0ULL);
}

View File

@@ -2,6 +2,8 @@
.global clks_exec_call_on_stack_x86_64 .global clks_exec_call_on_stack_x86_64
.type clks_exec_call_on_stack_x86_64, @function .type clks_exec_call_on_stack_x86_64, @function
.global clks_exec_abort_to_caller_x86_64
.type clks_exec_abort_to_caller_x86_64, @function
clks_exec_call_on_stack_x86_64: clks_exec_call_on_stack_x86_64:
mov r11, rsp mov r11, rsp
@@ -16,4 +18,12 @@ clks_exec_call_on_stack_x86_64:
ret ret
.size clks_exec_call_on_stack_x86_64, .-clks_exec_call_on_stack_x86_64 .size clks_exec_call_on_stack_x86_64, .-clks_exec_call_on_stack_x86_64
clks_exec_abort_to_caller_x86_64:
mov rax, rsi
mov rsp, rdi
mov rsp, [rsp]
ret
.size clks_exec_abort_to_caller_x86_64, .-clks_exec_abort_to_caller_x86_64
.section .note.GNU-stack,"",@progbits .section .note.GNU-stack,"",@progbits

View File

@@ -5,11 +5,27 @@
void clks_exec_init(void); void clks_exec_init(void);
clks_bool clks_exec_run_path(const char *path, u64 *out_status); 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_spawn_path(const char *path, u64 *out_pid); 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); u64 clks_exec_wait_pid(u64 pid, u64 *out_status);
clks_bool clks_exec_request_exit(u64 status); clks_bool clks_exec_request_exit(u64 status);
u64 clks_exec_current_pid(void); u64 clks_exec_current_pid(void);
u32 clks_exec_current_tty(void); u32 clks_exec_current_tty(void);
u64 clks_exec_current_argc(void);
clks_bool clks_exec_copy_current_argv(u64 index, char *out_value, usize out_size);
u64 clks_exec_current_envc(void);
clks_bool clks_exec_copy_current_env(u64 index, char *out_value, usize out_size);
u64 clks_exec_current_signal(void);
u64 clks_exec_current_fault_vector(void);
u64 clks_exec_current_fault_error(void);
u64 clks_exec_current_fault_rip(void);
clks_bool clks_exec_handle_exception(u64 vector,
u64 error_code,
u64 rip,
u64 *io_rip,
u64 *io_rdi,
u64 *io_rsi);
u64 clks_exec_sleep_ticks(u64 ticks); u64 clks_exec_sleep_ticks(u64 ticks);
u64 clks_exec_yield(void); u64 clks_exec_yield(void);
void clks_exec_tick(u64 tick); void clks_exec_tick(u64 tick);

View File

@@ -54,9 +54,19 @@
#define CLKS_SYSCALL_AUDIO_AVAILABLE 48ULL #define CLKS_SYSCALL_AUDIO_AVAILABLE 48ULL
#define CLKS_SYSCALL_AUDIO_PLAY_TONE 49ULL #define CLKS_SYSCALL_AUDIO_PLAY_TONE 49ULL
#define CLKS_SYSCALL_AUDIO_STOP 50ULL #define CLKS_SYSCALL_AUDIO_STOP 50ULL
#define CLKS_SYSCALL_EXEC_PATHV 51ULL
#define CLKS_SYSCALL_SPAWN_PATHV 52ULL
#define CLKS_SYSCALL_PROC_ARGC 53ULL
#define CLKS_SYSCALL_PROC_ARGV 54ULL
#define CLKS_SYSCALL_PROC_ENVC 55ULL
#define CLKS_SYSCALL_PROC_ENV 56ULL
#define CLKS_SYSCALL_PROC_LAST_SIGNAL 57ULL
#define CLKS_SYSCALL_PROC_FAULT_VECTOR 58ULL
#define CLKS_SYSCALL_PROC_FAULT_ERROR 59ULL
#define CLKS_SYSCALL_PROC_FAULT_RIP 60ULL
void clks_syscall_init(void); void clks_syscall_init(void);
u64 clks_syscall_dispatch(void *frame_ptr); u64 clks_syscall_dispatch(void *frame_ptr);
u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2); u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2);
#endif #endif

View File

@@ -16,6 +16,12 @@ typedef u64 (*clks_exec_entry_fn)(void);
#define CLKS_EXEC_MAX_PROCS 64U #define CLKS_EXEC_MAX_PROCS 64U
#define CLKS_EXEC_MAX_DEPTH 16U #define CLKS_EXEC_MAX_DEPTH 16U
#define CLKS_EXEC_PATH_MAX 192U #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)
enum clks_exec_proc_state { enum clks_exec_proc_state {
CLKS_EXEC_PROC_UNUSED = 0, CLKS_EXEC_PROC_UNUSED = 0,
@@ -34,10 +40,21 @@ struct clks_exec_proc_record {
u64 exit_status; u64 exit_status;
u32 tty_index; u32 tty_index;
char path[CLKS_EXEC_PATH_MAX]; 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) #if defined(CLKS_ARCH_X86_64)
extern u64 clks_exec_call_on_stack_x86_64(void *entry_ptr, void *stack_top); 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 #endif
static u64 clks_exec_requests = 0ULL; static u64 clks_exec_requests = 0ULL;
@@ -50,6 +67,8 @@ static u64 clks_exec_next_pid = 1ULL;
static u64 clks_exec_pid_stack[CLKS_EXEC_MAX_DEPTH]; static u64 clks_exec_pid_stack[CLKS_EXEC_MAX_DEPTH];
static clks_bool clks_exec_exit_requested_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 u64 clks_exec_exit_status_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 u32 clks_exec_pid_stack_depth = 0U; static u32 clks_exec_pid_stack_depth = 0U;
static void clks_exec_serial_write_hex64(u64 value) { static void clks_exec_serial_write_hex64(u64 value) {
@@ -163,6 +182,155 @@ static void clks_exec_copy_path(char *dst, usize dst_size, const char *src) {
dst[i] = '\0'; 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) { static i32 clks_exec_proc_find_slot_by_pid(u64 pid) {
u32 i; u32 i;
@@ -225,6 +393,8 @@ static u64 clks_exec_alloc_pid(void) {
static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot, static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot,
u64 pid, u64 pid,
const char *path, const char *path,
const char *argv_line,
const char *env_line,
enum clks_exec_proc_state state) { enum clks_exec_proc_state state) {
struct clks_exec_proc_record *proc; struct clks_exec_proc_record *proc;
@@ -244,10 +414,36 @@ static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot,
proc->exit_status = (u64)-1; proc->exit_status = (u64)-1;
proc->tty_index = clks_tty_active(); proc->tty_index = clks_tty_active();
clks_exec_copy_path(proc->path, sizeof(proc->path), path); 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; return proc;
} }
static clks_bool clks_exec_invoke_entry(void *entry_ptr, u64 *out_ret) { 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) { if (entry_ptr == CLKS_NULL || out_ret == CLKS_NULL) {
return CLKS_FALSE; return CLKS_FALSE;
} }
@@ -256,6 +452,7 @@ static clks_bool clks_exec_invoke_entry(void *entry_ptr, u64 *out_ret) {
{ {
void *stack_base = clks_kmalloc((usize)CLKS_EXEC_RUN_STACK_BYTES); void *stack_base = clks_kmalloc((usize)CLKS_EXEC_RUN_STACK_BYTES);
void *stack_top; void *stack_top;
u64 unwind_slot;
if (stack_base == CLKS_NULL) { if (stack_base == CLKS_NULL) {
clks_log(CLKS_LOG_WARN, "EXEC", "RUN STACK ALLOC FAILED"); clks_log(CLKS_LOG_WARN, "EXEC", "RUN STACK ALLOC FAILED");
@@ -263,11 +460,17 @@ static clks_bool clks_exec_invoke_entry(void *entry_ptr, u64 *out_ret) {
} }
stack_top = (void *)((u8 *)stack_base + (usize)CLKS_EXEC_RUN_STACK_BYTES); stack_top = (void *)((u8 *)stack_base + (usize)CLKS_EXEC_RUN_STACK_BYTES);
unwind_slot = (((u64)stack_top) & ~0xFULL) - 8ULL;
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); *out_ret = clks_exec_call_on_stack_x86_64(entry_ptr, stack_top);
clks_exec_unwind_slot_valid_stack[depth_index] = CLKS_FALSE;
clks_exec_unwind_slot_stack[depth_index] = 0ULL;
clks_kfree(stack_base); clks_kfree(stack_base);
return CLKS_TRUE; return CLKS_TRUE;
} }
#else #else
(void)depth_index;
*out_ret = ((clks_exec_entry_fn)entry_ptr)(); *out_ret = ((clks_exec_entry_fn)entry_ptr)();
return CLKS_TRUE; return CLKS_TRUE;
#endif #endif
@@ -364,7 +567,7 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) {
clks_exec_running_depth++; clks_exec_running_depth++;
depth_counted = CLKS_TRUE; depth_counted = CLKS_TRUE;
if (clks_exec_invoke_entry(entry_ptr, &run_ret) == CLKS_FALSE) { 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", "EXEC RUN INVOKE FAILED");
clks_log(CLKS_LOG_WARN, "EXEC", proc->path); clks_log(CLKS_LOG_WARN, "EXEC", proc->path);
goto fail; goto fail;
@@ -450,7 +653,11 @@ static clks_bool clks_exec_dispatch_pending_once(void) {
return CLKS_FALSE; return CLKS_FALSE;
} }
static clks_bool clks_exec_run_path_internal(const char *path, u64 *out_status, u64 *out_pid) { 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; i32 slot;
u64 pid; u64 pid;
struct clks_exec_proc_record *proc; struct clks_exec_proc_record *proc;
@@ -479,7 +686,7 @@ static clks_bool clks_exec_run_path_internal(const char *path, u64 *out_status,
} }
pid = clks_exec_alloc_pid(); pid = clks_exec_alloc_pid();
proc = clks_exec_prepare_proc_record(slot, pid, path, CLKS_EXEC_PROC_RUNNING); proc = clks_exec_prepare_proc_record(slot, pid, path, argv_line, env_line, CLKS_EXEC_PROC_RUNNING);
if (proc == CLKS_NULL) { if (proc == CLKS_NULL) {
return CLKS_FALSE; return CLKS_FALSE;
@@ -510,15 +717,21 @@ void clks_exec_init(void) {
clks_memset(clks_exec_pid_stack, 0, sizeof(clks_exec_pid_stack)); 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_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_exit_status_stack, 0, sizeof(clks_exec_exit_status_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_proc_table, 0, sizeof(clks_exec_proc_table)); clks_memset(clks_exec_proc_table, 0, sizeof(clks_exec_proc_table));
clks_exec_log_info_serial("PATH EXEC FRAMEWORK ONLINE"); clks_exec_log_info_serial("PATH EXEC FRAMEWORK ONLINE");
} }
clks_bool clks_exec_run_path(const char *path, u64 *out_status) { clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
return clks_exec_run_path_internal(path, out_status, CLKS_NULL); return clks_exec_run_path_internal(path, CLKS_NULL, CLKS_NULL, out_status, CLKS_NULL);
} }
clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) { 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; i32 slot;
u64 pid; u64 pid;
struct clks_exec_proc_record *proc; struct clks_exec_proc_record *proc;
@@ -542,7 +755,7 @@ clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) {
} }
pid = clks_exec_alloc_pid(); pid = clks_exec_alloc_pid();
proc = clks_exec_prepare_proc_record(slot, pid, path, CLKS_EXEC_PROC_PENDING); proc = clks_exec_prepare_proc_record(slot, pid, path, argv_line, env_line, CLKS_EXEC_PROC_PENDING);
if (proc == CLKS_NULL) { if (proc == CLKS_NULL) {
return CLKS_FALSE; return CLKS_FALSE;
@@ -559,6 +772,10 @@ clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) {
return CLKS_TRUE; 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) { u64 clks_exec_wait_pid(u64 pid, u64 *out_status) {
i32 slot; i32 slot;
struct clks_exec_proc_record *proc; struct clks_exec_proc_record *proc;
@@ -650,6 +867,159 @@ u32 clks_exec_current_tty(void) {
return proc->tty_index; 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;
}
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;
}
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 clks_exec_sleep_ticks(u64 ticks) {
u64 start = clks_interrupts_timer_ticks(); u64 start = clks_interrupts_timer_ticks();

View File

@@ -1,5 +1,6 @@
#include <clks/compiler.h> #include <clks/compiler.h>
#include <clks/cpu.h> #include <clks/cpu.h>
#include <clks/exec.h>
#include <clks/interrupts.h> #include <clks/interrupts.h>
#include <clks/log.h> #include <clks/log.h>
#include <clks/keyboard.h> #include <clks/keyboard.h>
@@ -250,6 +251,15 @@ void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) {
} }
if (vector < 32U) { if (vector < 32U) {
if (clks_exec_handle_exception(vector,
frame->error_code,
frame->rip,
&frame->rip,
&frame->rdi,
&frame->rsi) == CLKS_TRUE) {
return;
}
clks_panic_exception(clks_exception_names[vector], vector, frame->error_code, frame->rip); clks_panic_exception(clks_exception_names[vector], vector, frame->error_code, frame->rip);
} }

View File

@@ -22,6 +22,9 @@
#define CLKS_SYSCALL_TTY_MAX_LEN 512U #define CLKS_SYSCALL_TTY_MAX_LEN 512U
#define CLKS_SYSCALL_FS_IO_MAX_LEN 65536U #define CLKS_SYSCALL_FS_IO_MAX_LEN 65536U
#define CLKS_SYSCALL_JOURNAL_MAX_LEN 256U #define CLKS_SYSCALL_JOURNAL_MAX_LEN 256U
#define CLKS_SYSCALL_ARG_LINE_MAX 256U
#define CLKS_SYSCALL_ENV_LINE_MAX 512U
#define CLKS_SYSCALL_ITEM_MAX 128U
#define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL #define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL
struct clks_syscall_frame { struct clks_syscall_frame {
@@ -87,6 +90,19 @@ static clks_bool clks_syscall_copy_user_string(u64 src_addr, char *dst, usize ds
return CLKS_TRUE; return CLKS_TRUE;
} }
static clks_bool clks_syscall_copy_user_optional_string(u64 src_addr, char *dst, usize dst_size) {
if (dst == CLKS_NULL || dst_size == 0U) {
return CLKS_FALSE;
}
if (src_addr == 0ULL) {
dst[0] = '\0';
return CLKS_TRUE;
}
return clks_syscall_copy_user_string(src_addr, dst, dst_size);
}
static u64 clks_syscall_log_write(u64 arg0, u64 arg1) { static u64 clks_syscall_log_write(u64 arg0, u64 arg1) {
const char *src = (const char *)arg0; const char *src = (const char *)arg0;
u64 len = arg1; u64 len = arg1;
@@ -218,6 +234,31 @@ static u64 clks_syscall_exec_path(u64 arg0) {
return status; return status;
} }
static u64 clks_syscall_exec_pathv(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];
u64 status = (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;
}
if (clks_syscall_copy_user_optional_string(arg2, env_line, sizeof(env_line)) == CLKS_FALSE) {
return (u64)-1;
}
if (clks_exec_run_pathv(path, argv_line, env_line, &status) == CLKS_FALSE) {
return (u64)-1;
}
return status;
}
static u64 clks_syscall_getpid(void) { static u64 clks_syscall_getpid(void) {
return clks_exec_current_pid(); return clks_exec_current_pid();
} }
@@ -237,6 +278,31 @@ static u64 clks_syscall_spawn_path(u64 arg0) {
return pid; return pid;
} }
static u64 clks_syscall_spawn_pathv(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];
u64 pid = (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;
}
if (clks_syscall_copy_user_optional_string(arg2, env_line, sizeof(env_line)) == CLKS_FALSE) {
return (u64)-1;
}
if (clks_exec_spawn_pathv(path, argv_line, env_line, &pid) == CLKS_FALSE) {
return (u64)-1;
}
return pid;
}
static u64 clks_syscall_waitpid(u64 arg0, u64 arg1) { static u64 clks_syscall_waitpid(u64 arg0, u64 arg1) {
u64 status = (u64)-1; u64 status = (u64)-1;
u64 wait_ret = clks_exec_wait_pid(arg0, &status); u64 wait_ret = clks_exec_wait_pid(arg0, &status);
@@ -248,6 +314,54 @@ static u64 clks_syscall_waitpid(u64 arg0, u64 arg1) {
return wait_ret; return wait_ret;
} }
static u64 clks_syscall_proc_argc(void) {
return clks_exec_current_argc();
}
static u64 clks_syscall_proc_argv(u64 arg0, u64 arg1, u64 arg2) {
if (arg1 == 0ULL || arg2 == 0ULL) {
return 0ULL;
}
if (arg2 > CLKS_SYSCALL_ITEM_MAX) {
arg2 = CLKS_SYSCALL_ITEM_MAX;
}
return (clks_exec_copy_current_argv(arg0, (char *)arg1, (usize)arg2) == CLKS_TRUE) ? 1ULL : 0ULL;
}
static u64 clks_syscall_proc_envc(void) {
return clks_exec_current_envc();
}
static u64 clks_syscall_proc_env(u64 arg0, u64 arg1, u64 arg2) {
if (arg1 == 0ULL || arg2 == 0ULL) {
return 0ULL;
}
if (arg2 > CLKS_SYSCALL_ITEM_MAX) {
arg2 = CLKS_SYSCALL_ITEM_MAX;
}
return (clks_exec_copy_current_env(arg0, (char *)arg1, (usize)arg2) == CLKS_TRUE) ? 1ULL : 0ULL;
}
static u64 clks_syscall_proc_last_signal(void) {
return clks_exec_current_signal();
}
static u64 clks_syscall_proc_fault_vector(void) {
return clks_exec_current_fault_vector();
}
static u64 clks_syscall_proc_fault_error(void) {
return clks_exec_current_fault_error();
}
static u64 clks_syscall_proc_fault_rip(void) {
return clks_exec_current_fault_rip();
}
static u64 clks_syscall_exit(u64 arg0) { static u64 clks_syscall_exit(u64 arg0) {
return (clks_exec_request_exit(arg0) == CLKS_TRUE) ? 1ULL : 0ULL; return (clks_exec_request_exit(arg0) == CLKS_TRUE) ? 1ULL : 0ULL;
} }
@@ -530,6 +644,8 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
return clks_syscall_fs_read(frame->rbx, frame->rcx, frame->rdx); return clks_syscall_fs_read(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_EXEC_PATH: case CLKS_SYSCALL_EXEC_PATH:
return clks_syscall_exec_path(frame->rbx); 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_REQUESTS: case CLKS_SYSCALL_EXEC_REQUESTS:
return clks_exec_request_count(); return clks_exec_request_count();
case CLKS_SYSCALL_EXEC_SUCCESS: case CLKS_SYSCALL_EXEC_SUCCESS:
@@ -587,8 +703,26 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
return clks_syscall_getpid(); return clks_syscall_getpid();
case CLKS_SYSCALL_SPAWN_PATH: case CLKS_SYSCALL_SPAWN_PATH:
return clks_syscall_spawn_path(frame->rbx); return clks_syscall_spawn_path(frame->rbx);
case CLKS_SYSCALL_SPAWN_PATHV:
return clks_syscall_spawn_pathv(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_WAITPID: case CLKS_SYSCALL_WAITPID:
return clks_syscall_waitpid(frame->rbx, frame->rcx); return clks_syscall_waitpid(frame->rbx, frame->rcx);
case CLKS_SYSCALL_PROC_ARGC:
return clks_syscall_proc_argc();
case CLKS_SYSCALL_PROC_ARGV:
return clks_syscall_proc_argv(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_PROC_ENVC:
return clks_syscall_proc_envc();
case CLKS_SYSCALL_PROC_ENV:
return clks_syscall_proc_env(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_PROC_LAST_SIGNAL:
return clks_syscall_proc_last_signal();
case CLKS_SYSCALL_PROC_FAULT_VECTOR:
return clks_syscall_proc_fault_vector();
case CLKS_SYSCALL_PROC_FAULT_ERROR:
return clks_syscall_proc_fault_error();
case CLKS_SYSCALL_PROC_FAULT_RIP:
return clks_syscall_proc_fault_rip();
case CLKS_SYSCALL_EXIT: case CLKS_SYSCALL_EXIT:
return clks_syscall_exit(frame->rbx); return clks_syscall_exit(frame->rbx);
case CLKS_SYSCALL_SLEEP_TICKS: case CLKS_SYSCALL_SLEEP_TICKS:

View File

@@ -8,16 +8,20 @@
## Implementation ## Implementation
- Added more user-facing commands in user shell around process/runtime control (`spawn`, `wait`, `sleep`, `yield`, `pid`, file ops under `/temp`). - Added more user-facing commands in user shell around process/runtime control (`spawn`, `wait`, `sleep`, `yield`, `pid`, file ops under `/temp`).
- Extended syscall surface (process and runtime related IDs) and kept kernel/user syscall ID tables aligned. - Extended syscall surface (process and runtime related IDs) and kept kernel/user syscall ID tables aligned.
- Added process argument/environment ABI (`EXEC_PATHV` / `SPAWN_PATHV` + `PROC_ARG*` / `PROC_ENV*`).
- Added user exception/fault reporting ABI (`PROC_LAST_SIGNAL` / `PROC_FAULT_*`) and signal-encoded exit status.
- Updated user runtime syscall wrappers to cover newly added syscall IDs. - Updated user runtime syscall wrappers to cover newly added syscall IDs.
- Refactored Wine codebase from single-file implementation into modular structure for CLI, ELF loader, syscall bridge, and runtime helpers. - Refactored Wine codebase from single-file implementation into modular structure for CLI, ELF loader, syscall bridge, and runtime helpers.
## Acceptance Criteria ## Acceptance Criteria
- User shell can complete process and temp-file workflows without falling back to kernel shell. - User shell can complete process and temp-file workflows without falling back to kernel shell.
- User ELF can read `argc/argv/envp` through runtime startup path.
- `wait` can observe signal-encoded status for crashed user processes.
- New syscall IDs are available consistently in: - New syscall IDs are available consistently in:
- `clks/include/clks/syscall.h` - `clks/include/clks/syscall.h`
- `cleonos/c/include/cleonos_syscall.h` - `cleonos/c/include/cleonos_syscall.h`
- `cleonos/c/src/syscall.c` - `cleonos/c/src/syscall.c`
- Wine entry remains runnable after split (`python cleonos_wine.py ...`). - Wine entry remains runnable after split (`python cleonos_wine.py ...`) and supports process/argv/env/fault syscalls.
## Build Targets ## Build Targets
- `make userapps` - `make userapps`

View File

@@ -36,6 +36,14 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 失败时多数接口返回 `0xFFFFFFFFFFFFFFFF`(即 `u64``-1`)。 - 失败时多数接口返回 `0xFFFFFFFFFFFFFFFF`(即 `u64``-1`)。
- 部分接口失败返回 `0`(例如 `FS_READ` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` / `LOG_JOURNAL_READ`)。 - 部分接口失败返回 `0`(例如 `FS_READ` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` / `LOG_JOURNAL_READ`)。
进程退出状态补充(`EXEC_PATH*` / `WAITPID`
- 普通退出:返回值即用户程序退出码。
- 异常终止:返回值最高位为 `1``1<<63`),并编码:
- bits `7:0` = signal
- bits `15:8` = CPU exception vector
- bits `31:16` = exception error code 低 16 位
## 3. 当前实现中的长度/路径限制 ## 3. 当前实现中的长度/路径限制
以下限制由内核 `clks/kernel/syscall.c` 当前实现决定: 以下限制由内核 `clks/kernel/syscall.c` 当前实现决定:
@@ -52,7 +60,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `FS_MKDIR` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` 仅允许 `/temp` 树下路径。 - `FS_MKDIR` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` 仅允许 `/temp` 树下路径。
## 4. Syscall 列表0~50 ## 4. Syscall 列表0~60
### 0 `CLEONOS_SYSCALL_LOG_WRITE` ### 0 `CLEONOS_SYSCALL_LOG_WRITE`
@@ -371,6 +379,73 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 返回:当前实现固定返回 `1` - 返回:当前实现固定返回 `1`
- 说明:立即停止当前音频输出。 - 说明:立即停止当前音频输出。
### 51 `CLEONOS_SYSCALL_EXEC_PATHV`
- 参数:
- `arg0`: `const char *path`
- `arg1`: `const char *argv_line`(可为 `0`
- `arg2`: `const char *env_line`(可为 `0`
- 返回:
- `-1`:请求失败
- 其他:目标程序退出状态
- 说明:`argv_line` 以空白分词,`env_line``;` 或换行分隔条目。
### 52 `CLEONOS_SYSCALL_SPAWN_PATHV`
- 参数:
- `arg0`: `const char *path`
- `arg1`: `const char *argv_line`(可为 `0`
- `arg2`: `const char *env_line`(可为 `0`
- 返回:成功为子进程 PID失败 `-1`
### 53 `CLEONOS_SYSCALL_PROC_ARGC`
- 参数:无
- 返回:当前进程 `argc`
### 54 `CLEONOS_SYSCALL_PROC_ARGV`
- 参数:
- `arg0`: `u64 index`
- `arg1`: `char *out_value`
- `arg2`: `u64 out_size`
- 返回:成功 `1`,失败 `0`
- 说明:单条参数字符串最大写入 `128` 字节(含终止符)。
### 55 `CLEONOS_SYSCALL_PROC_ENVC`
- 参数:无
- 返回:当前进程 `envc`
### 56 `CLEONOS_SYSCALL_PROC_ENV`
- 参数:
- `arg0`: `u64 index`
- `arg1`: `char *out_value`
- `arg2`: `u64 out_size`
- 返回:成功 `1`,失败 `0`
- 说明:单条环境变量字符串最大写入 `128` 字节(含终止符)。
### 57 `CLEONOS_SYSCALL_PROC_LAST_SIGNAL`
- 参数:无
- 返回:当前进程最近一次异常映射的信号号(无则 `0`
### 58 `CLEONOS_SYSCALL_PROC_FAULT_VECTOR`
- 参数:无
- 返回:当前进程最近一次 CPU 异常向量号(无则 `0`
### 59 `CLEONOS_SYSCALL_PROC_FAULT_ERROR`
- 参数:无
- 返回:当前进程最近一次 CPU 异常错误码(无则 `0`
### 60 `CLEONOS_SYSCALL_PROC_FAULT_RIP`
- 参数:无
- 返回:当前进程最近一次 CPU 异常 RIP无则 `0`
## 5. 用户态封装函数 ## 5. 用户态封装函数
用户态封装位于: 用户态封装位于:
@@ -383,14 +458,24 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `cleonos_sys_fs_write()` / `cleonos_sys_fs_append()` / `cleonos_sys_fs_remove()` - `cleonos_sys_fs_write()` / `cleonos_sys_fs_append()` / `cleonos_sys_fs_remove()`
- `cleonos_sys_log_journal_count()` / `cleonos_sys_log_journal_read()` - `cleonos_sys_log_journal_count()` / `cleonos_sys_log_journal_read()`
- `cleonos_sys_exec_path()` - `cleonos_sys_exec_path()`
- `cleonos_sys_exec_pathv()`
- `cleonos_sys_tty_write()` - `cleonos_sys_tty_write()`
- `cleonos_sys_kbd_get_char()` / `cleonos_sys_kbd_buffered()` - `cleonos_sys_kbd_get_char()` / `cleonos_sys_kbd_buffered()`
- `cleonos_sys_getpid()` / `cleonos_sys_spawn_path()` / `cleonos_sys_wait_pid()` - `cleonos_sys_getpid()` / `cleonos_sys_spawn_path()` / `cleonos_sys_wait_pid()`
- `cleonos_sys_spawn_pathv()`
- `cleonos_sys_exit()` / `cleonos_sys_sleep_ticks()` / `cleonos_sys_yield()` / `cleonos_sys_shutdown()` / `cleonos_sys_restart()` - `cleonos_sys_exit()` / `cleonos_sys_sleep_ticks()` / `cleonos_sys_yield()` / `cleonos_sys_shutdown()` / `cleonos_sys_restart()`
- `cleonos_sys_audio_available()` / `cleonos_sys_audio_play_tone()` / `cleonos_sys_audio_stop()` - `cleonos_sys_audio_available()` / `cleonos_sys_audio_play_tone()` / `cleonos_sys_audio_stop()`
- `cleonos_sys_proc_argc()` / `cleonos_sys_proc_argv()` / `cleonos_sys_proc_envc()` / `cleonos_sys_proc_env()`
- `cleonos_sys_proc_last_signal()` / `cleonos_sys_proc_fault_vector()` / `cleonos_sys_proc_fault_error()` / `cleonos_sys_proc_fault_rip()`
## 6. 开发注意事项 ## 6. 开发注意事项
- 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。 - 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。
- `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'` - `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`
- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。 - `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。
## 7. Wine 兼容说明
- `wine/cleonos_wine_lib/runner.py` 已适配 syscall `0..60`,包含 `EXEC_PATHV` / `SPAWN_PATHV``PROC_*` 系列。
- Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。
- Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0``AUDIO_PLAY_TONE=0``AUDIO_STOP=1`

View File

@@ -37,15 +37,31 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
## 支持 ## 支持
- ELF64 (x86_64) PT_LOAD 段装载 - ELF64 (x86_64) PT_LOAD 段装载
- CLeonOS `int 0x80` syscall 0..45 - CLeonOS `int 0x80` syscall 0..60
- TTY 输出与键盘输入队列 - TTY 输出与键盘输入队列
- rootfs 文件/目录访问(`FS_*` - rootfs 文件/目录访问(`FS_*`
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE` - `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`
- `EXEC_PATH` 递归执行 ELF带深度限制 - `EXEC_PATH/EXEC_PATHV` 执行 ELF带深度限制
- 进程生命周期 syscall`GETPID/SPAWN_PATH/WAITPID/EXIT/SLEEP_TICKS/YIELD` - `SPAWN_PATH/SPAWN_PATHV/WAITPID/EXIT/SLEEP_TICKS/YIELD`
- 进程 `argv/env` 查询(`PROC_ARGC/PROC_ARGV/PROC_ENVC/PROC_ENV`
- 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*`
## 参数 ## 参数
- `--no-kbd`:关闭输入线程 - `--no-kbd`:关闭输入线程
- `--max-exec-depth N`:设置 exec 嵌套深度上限 - `--max-exec-depth N`:设置 exec 嵌套深度上限
- `--verbose`:打印更多日志`n - `--verbose`:打印更多日志
## `execv/spawnv` 参数格式
- `argv_line`:按空白字符分词(与内核当前实现一致,不支持引号转义)。
- `env_line`:按 `;` 或换行切分环境变量项,会去掉每项末尾空白。
- 子进程 `argv[0]` 固定为目标程序路径(如 `/shell/ls.elf`)。
## 退出状态说明
- 正常退出:返回普通退出码。
- 异常退出:最高位为 `1`,并编码:
- bits `7:0` = signal
- bits `15:8` = CPU exception vector
- bits `31:16` = error code 低 16 位

Binary file not shown.

View File

@@ -56,6 +56,19 @@ SYS_SLEEP_TICKS = 44
SYS_YIELD = 45 SYS_YIELD = 45
SYS_SHUTDOWN = 46 SYS_SHUTDOWN = 46
SYS_RESTART = 47 SYS_RESTART = 47
SYS_AUDIO_AVAILABLE = 48
SYS_AUDIO_PLAY_TONE = 49
SYS_AUDIO_STOP = 50
SYS_EXEC_PATHV = 51
SYS_SPAWN_PATHV = 52
SYS_PROC_ARGC = 53
SYS_PROC_ARGV = 54
SYS_PROC_ENVC = 55
SYS_PROC_ENV = 56
SYS_PROC_LAST_SIGNAL = 57
SYS_PROC_FAULT_VECTOR = 58
SYS_PROC_FAULT_ERROR = 59
SYS_PROC_FAULT_RIP = 60
def u64(value: int) -> int: def u64(value: int) -> int:
@@ -71,4 +84,4 @@ def page_floor(addr: int) -> int:
def page_ceil(addr: int) -> int: def page_ceil(addr: int) -> int:
return (addr + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1) return (addr + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)

View File

@@ -7,12 +7,22 @@ try:
from unicorn import UC_ARCH_X86, UC_MODE_64 from unicorn import UC_ARCH_X86, UC_MODE_64
from unicorn import UC_HOOK_CODE, UC_HOOK_INTR from unicorn import UC_HOOK_CODE, UC_HOOK_INTR
from unicorn import UC_PROT_ALL, UC_PROT_EXEC, UC_PROT_READ, UC_PROT_WRITE from unicorn import UC_PROT_ALL, UC_PROT_EXEC, UC_PROT_READ, UC_PROT_WRITE
from unicorn import (
UC_ERR_FETCH_PROT,
UC_ERR_FETCH_UNMAPPED,
UC_ERR_INSN_INVALID,
UC_ERR_READ_PROT,
UC_ERR_READ_UNMAPPED,
UC_ERR_WRITE_PROT,
UC_ERR_WRITE_UNMAPPED,
)
from unicorn.x86_const import ( from unicorn.x86_const import (
UC_X86_REG_RAX, UC_X86_REG_RAX,
UC_X86_REG_RBX, UC_X86_REG_RBX,
UC_X86_REG_RCX, UC_X86_REG_RCX,
UC_X86_REG_RDX, UC_X86_REG_RDX,
UC_X86_REG_RBP, UC_X86_REG_RBP,
UC_X86_REG_RIP,
UC_X86_REG_RSP, UC_X86_REG_RSP,
) )
except Exception as exc: except Exception as exc:
@@ -32,10 +42,18 @@ __all__ = [
"UC_PROT_EXEC", "UC_PROT_EXEC",
"UC_PROT_READ", "UC_PROT_READ",
"UC_PROT_WRITE", "UC_PROT_WRITE",
"UC_ERR_FETCH_PROT",
"UC_ERR_FETCH_UNMAPPED",
"UC_ERR_INSN_INVALID",
"UC_ERR_READ_PROT",
"UC_ERR_READ_UNMAPPED",
"UC_ERR_WRITE_PROT",
"UC_ERR_WRITE_UNMAPPED",
"UC_X86_REG_RAX", "UC_X86_REG_RAX",
"UC_X86_REG_RBX", "UC_X86_REG_RBX",
"UC_X86_REG_RCX", "UC_X86_REG_RCX",
"UC_X86_REG_RDX", "UC_X86_REG_RDX",
"UC_X86_REG_RBP", "UC_X86_REG_RBP",
"UC_X86_REG_RIP",
"UC_X86_REG_RSP", "UC_X86_REG_RSP",
] ]

View File

@@ -14,15 +14,28 @@ from .constants import (
MAX_CSTR, MAX_CSTR,
MAX_IO_READ, MAX_IO_READ,
PAGE_SIZE, PAGE_SIZE,
SYS_AUDIO_AVAILABLE,
SYS_AUDIO_PLAY_TONE,
SYS_AUDIO_STOP,
SYS_CONTEXT_SWITCHES, SYS_CONTEXT_SWITCHES,
SYS_CUR_TASK, SYS_CUR_TASK,
SYS_EXEC_PATH, SYS_EXEC_PATH,
SYS_EXEC_PATHV,
SYS_EXEC_REQUESTS, SYS_EXEC_REQUESTS,
SYS_EXEC_SUCCESS, SYS_EXEC_SUCCESS,
SYS_EXIT, SYS_EXIT,
SYS_GETPID, SYS_GETPID,
SYS_PROC_ARGC,
SYS_PROC_ARGV,
SYS_PROC_ENVC,
SYS_PROC_ENV,
SYS_PROC_FAULT_ERROR,
SYS_PROC_FAULT_RIP,
SYS_PROC_FAULT_VECTOR,
SYS_PROC_LAST_SIGNAL,
SYS_SLEEP_TICKS, SYS_SLEEP_TICKS,
SYS_SPAWN_PATH, SYS_SPAWN_PATH,
SYS_SPAWN_PATHV,
SYS_WAITPID, SYS_WAITPID,
SYS_YIELD, SYS_YIELD,
SYS_SHUTDOWN, SYS_SHUTDOWN,
@@ -72,6 +85,13 @@ from .platform import (
Uc, Uc,
UcError, UcError,
UC_ARCH_X86, UC_ARCH_X86,
UC_ERR_FETCH_PROT,
UC_ERR_FETCH_UNMAPPED,
UC_ERR_INSN_INVALID,
UC_ERR_READ_PROT,
UC_ERR_READ_UNMAPPED,
UC_ERR_WRITE_PROT,
UC_ERR_WRITE_UNMAPPED,
UC_HOOK_CODE, UC_HOOK_CODE,
UC_HOOK_INTR, UC_HOOK_INTR,
UC_MODE_64, UC_MODE_64,
@@ -85,6 +105,7 @@ from .platform import (
UC_X86_REG_RCX, UC_X86_REG_RCX,
UC_X86_REG_RDX, UC_X86_REG_RDX,
UC_X86_REG_RSP, UC_X86_REG_RSP,
UC_X86_REG_RIP,
) )
from .state import SharedKernelState from .state import SharedKernelState
@@ -103,6 +124,15 @@ class ELFImage:
segments: List[ELFSegment] segments: List[ELFSegment]
EXEC_PATH_MAX = 192
EXEC_ARG_LINE_MAX = 256
EXEC_ENV_LINE_MAX = 512
EXEC_MAX_ARGS = 24
EXEC_MAX_ENVS = 24
EXEC_ITEM_MAX = 128
EXEC_STATUS_SIGNAL_FLAG = 1 << 63
class CLeonOSWineNative: class CLeonOSWineNative:
def __init__( def __init__(
self, self,
@@ -118,6 +148,8 @@ class CLeonOSWineNative:
top_level: bool = True, top_level: bool = True,
pid: int = 0, pid: int = 0,
ppid: int = 0, ppid: int = 0,
argv_items: Optional[List[str]] = None,
env_items: Optional[List[str]] = None,
) -> None: ) -> None:
self.elf_path = elf_path self.elf_path = elf_path
self.rootfs = rootfs self.rootfs = rootfs
@@ -130,6 +162,8 @@ class CLeonOSWineNative:
self.top_level = top_level self.top_level = top_level
self.pid = int(pid) self.pid = int(pid)
self.ppid = int(ppid) self.ppid = int(ppid)
self.argv_items = list(argv_items) if argv_items is not None else []
self.env_items = list(env_items) if env_items is not None else []
self._exit_requested = False self._exit_requested = False
self._exit_status = 0 self._exit_status = 0
@@ -142,12 +176,17 @@ class CLeonOSWineNative:
self._ret_sentinel = 0x00007FFF10000000 self._ret_sentinel = 0x00007FFF10000000
self._mapped_ranges: List[Tuple[int, int]] = [] self._mapped_ranges: List[Tuple[int, int]] = []
default_path = self._normalize_guest_path(self.guest_path_hint or f"/{self.elf_path.name}")
self.argv_items, self.env_items = self._prepare_exec_items(default_path, self.argv_items, self.env_items)
def run(self) -> Optional[int]: def run(self) -> Optional[int]:
if self.pid == 0: if self.pid == 0:
self.pid = self.state.alloc_pid(self.ppid) self.pid = self.state.alloc_pid(self.ppid)
prev_pid = self.state.get_current_pid() prev_pid = self.state.get_current_pid()
self.state.set_current_pid(self.pid) self.state.set_current_pid(self.pid)
self.state.set_proc_cmdline(self.pid, self.argv_items, self.env_items)
self.state.set_proc_fault(self.pid, 0, 0, 0, 0)
uc = Uc(UC_ARCH_X86, UC_MODE_64) uc = Uc(UC_ARCH_X86, UC_MODE_64)
self._install_hooks(uc) self._install_hooks(uc)
@@ -158,27 +197,31 @@ class CLeonOSWineNative:
self._input_pump = InputPump(self.state) self._input_pump = InputPump(self.state)
self._input_pump.start() self._input_pump.start()
run_failed = False interrupted = False
runtime_fault_status: Optional[int] = None
try: try:
uc.emu_start(self.image.entry, 0) uc.emu_start(self.image.entry, 0)
except KeyboardInterrupt: except KeyboardInterrupt:
run_failed = True interrupted = True
if self.top_level: if self.top_level:
print("\n[WINE] interrupted by user", file=sys.stderr) print("\n[WINE] interrupted by user", file=sys.stderr)
except UcError as exc: except UcError as exc:
run_failed = True runtime_fault_status = self._status_from_uc_error(uc, exc)
if self.verbose or self.top_level: if self.verbose or self.top_level:
print(f"[WINE][ERROR] runtime crashed: {exc}", file=sys.stderr) print(f"[WINE][ERROR] runtime crashed: {exc}", file=sys.stderr)
finally: finally:
if self.top_level and self._input_pump is not None: if self.top_level and self._input_pump is not None:
self._input_pump.stop() self._input_pump.stop()
if run_failed: if interrupted:
self.state.mark_exited(self.pid, u64_neg1()) self.state.mark_exited(self.pid, u64_neg1())
self.state.set_current_pid(prev_pid) self.state.set_current_pid(prev_pid)
return None return None
if runtime_fault_status is not None:
self.exit_code = runtime_fault_status
if self.exit_code is None: if self.exit_code is None:
self.exit_code = self._reg_read(uc, UC_X86_REG_RAX) self.exit_code = self._reg_read(uc, UC_X86_REG_RAX)
@@ -246,18 +289,44 @@ class CLeonOSWineNative:
return self._fs_read(uc, arg0, arg1, arg2) return self._fs_read(uc, arg0, arg1, arg2)
if sid == SYS_EXEC_PATH: if sid == SYS_EXEC_PATH:
return self._exec_path(uc, arg0) return self._exec_path(uc, arg0)
if sid == SYS_EXEC_PATHV:
return self._exec_pathv(uc, arg0, arg1, arg2)
if sid == SYS_SPAWN_PATH: if sid == SYS_SPAWN_PATH:
return self._spawn_path(uc, arg0) return self._spawn_path(uc, arg0)
if sid == SYS_SPAWN_PATHV:
return self._spawn_pathv(uc, arg0, arg1, arg2)
if sid == SYS_WAITPID: if sid == SYS_WAITPID:
return self._wait_pid(uc, arg0, arg1) return self._wait_pid(uc, arg0, arg1)
if sid == SYS_GETPID: if sid == SYS_GETPID:
return self.state.get_current_pid() return self.state.get_current_pid()
if sid == SYS_PROC_ARGC:
return self._proc_argc()
if sid == SYS_PROC_ARGV:
return self._proc_argv(uc, arg0, arg1, arg2)
if sid == SYS_PROC_ENVC:
return self._proc_envc()
if sid == SYS_PROC_ENV:
return self._proc_env(uc, arg0, arg1, arg2)
if sid == SYS_PROC_LAST_SIGNAL:
return self._proc_last_signal()
if sid == SYS_PROC_FAULT_VECTOR:
return self._proc_fault_vector()
if sid == SYS_PROC_FAULT_ERROR:
return self._proc_fault_error()
if sid == SYS_PROC_FAULT_RIP:
return self._proc_fault_rip()
if sid == SYS_EXIT: if sid == SYS_EXIT:
return self._request_exit(uc, arg0) return self._request_exit(uc, arg0)
if sid == SYS_SLEEP_TICKS: if sid == SYS_SLEEP_TICKS:
return self._sleep_ticks(arg0) return self._sleep_ticks(arg0)
if sid == SYS_YIELD: if sid == SYS_YIELD:
return self._yield_once() return self._yield_once()
if sid == SYS_AUDIO_AVAILABLE:
return 0
if sid == SYS_AUDIO_PLAY_TONE:
return 0
if sid == SYS_AUDIO_STOP:
return 1
if sid == SYS_SHUTDOWN: if sid == SYS_SHUTDOWN:
self._host_write("\n[WINE] shutdown requested by guest\n") self._host_write("\n[WINE] shutdown requested by guest\n")
self._exit_requested = True self._exit_requested = True
@@ -674,14 +743,30 @@ class CLeonOSWineNative:
return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0 return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0
def _exec_path(self, uc: Uc, path_ptr: int) -> int: def _exec_path(self, uc: Uc, path_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, return_pid=False) return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=False)
def _exec_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, argv_ptr, env_ptr, return_pid=False)
def _spawn_path(self, uc: Uc, path_ptr: int) -> int: def _spawn_path(self, uc: Uc, path_ptr: int) -> int:
return self._spawn_path_common(uc, path_ptr, return_pid=True) return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=True)
def _spawn_path_common(self, uc: Uc, path_ptr: int, *, return_pid: bool) -> int: def _spawn_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int:
path = self._read_guest_cstring(uc, path_ptr) return self._spawn_path_common(uc, path_ptr, argv_ptr, env_ptr, return_pid=True)
def _spawn_path_common(
self,
uc: Uc,
path_ptr: int,
argv_ptr: int,
env_ptr: int,
*,
return_pid: bool,
) -> int:
path = self._read_guest_cstring(uc, path_ptr, EXEC_PATH_MAX)
guest_path = self._normalize_guest_path(path) guest_path = self._normalize_guest_path(path)
argv_line = self._read_guest_cstring(uc, argv_ptr, EXEC_ARG_LINE_MAX) if argv_ptr != 0 else ""
env_line = self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else ""
host_path = self._guest_to_host(guest_path, must_exist=True) host_path = self._guest_to_host(guest_path, must_exist=True)
self.state.exec_requests = u64(self.state.exec_requests + 1) self.state.exec_requests = u64(self.state.exec_requests + 1)
@@ -699,6 +784,9 @@ class CLeonOSWineNative:
parent_pid = self.state.get_current_pid() parent_pid = self.state.get_current_pid()
child_pid = self.state.alloc_pid(parent_pid) child_pid = self.state.alloc_pid(parent_pid)
argv_items, env_items = self._build_child_exec_items(guest_path, argv_line, env_line)
self.state.set_proc_cmdline(child_pid, argv_items, env_items)
self.state.set_proc_fault(child_pid, 0, 0, 0, 0)
child = CLeonOSWineNative( child = CLeonOSWineNative(
elf_path=host_path, elf_path=host_path,
@@ -712,6 +800,8 @@ class CLeonOSWineNative:
top_level=False, top_level=False,
pid=child_pid, pid=child_pid,
ppid=parent_pid, ppid=parent_pid,
argv_items=argv_items,
env_items=env_items,
) )
child_ret = child.run() child_ret = child.run()
@@ -728,7 +818,41 @@ class CLeonOSWineNative:
if return_pid: if return_pid:
return child_pid return child_pid
return 0 return u64(child_ret)
def _proc_argc(self) -> int:
return self.state.proc_argc(self.state.get_current_pid())
def _proc_argv(self, uc: Uc, index: int, out_ptr: int, out_size: int) -> int:
return self._copy_proc_item_to_guest(
uc,
self.state.proc_argv_item(self.state.get_current_pid(), int(index)),
out_ptr,
out_size,
)
def _proc_envc(self) -> int:
return self.state.proc_envc(self.state.get_current_pid())
def _proc_env(self, uc: Uc, index: int, out_ptr: int, out_size: int) -> int:
return self._copy_proc_item_to_guest(
uc,
self.state.proc_env_item(self.state.get_current_pid(), int(index)),
out_ptr,
out_size,
)
def _proc_last_signal(self) -> int:
return self.state.proc_signal(self.state.get_current_pid())
def _proc_fault_vector(self) -> int:
return self.state.proc_fault_vector_value(self.state.get_current_pid())
def _proc_fault_error(self) -> int:
return self.state.proc_fault_error_value(self.state.get_current_pid())
def _proc_fault_rip(self) -> int:
return self.state.proc_fault_rip_value(self.state.get_current_pid())
def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int: def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int:
wait_ret, status = self.state.wait_pid(int(pid)) wait_ret, status = self.state.wait_pid(int(pid))
@@ -761,6 +885,157 @@ class CLeonOSWineNative:
time.sleep(0) time.sleep(0)
return self.state.timer_ticks() return self.state.timer_ticks()
@staticmethod
def _truncate_item_text(text: str, max_bytes: int = EXEC_ITEM_MAX) -> str:
if max_bytes <= 1:
return ""
encoded = (text or "").encode("utf-8", errors="replace")
if len(encoded) >= max_bytes:
encoded = encoded[: max_bytes - 1]
return encoded.decode("utf-8", errors="ignore")
@staticmethod
def _parse_whitespace_items(line: str, max_count: int) -> List[str]:
out: List[str] = []
i = 0
text = line or ""
length = len(text)
while i < length:
while i < length and text[i] in (" ", "\t", "\r", "\n"):
i += 1
if i >= length:
break
start = i
while i < length and text[i] not in (" ", "\t", "\r", "\n"):
i += 1
out.append(text[start:i])
if len(out) >= max_count:
break
return out
@staticmethod
def _parse_env_items(line: str, max_count: int) -> List[str]:
out: List[str] = []
i = 0
text = line or ""
length = len(text)
while i < length:
while i < length and text[i] in (" ", "\t", ";", "\r", "\n"):
i += 1
if i >= length:
break
start = i
while i < length and text[i] not in (";", "\r", "\n"):
i += 1
value = text[start:i].rstrip(" \t")
if value:
out.append(value)
if len(out) >= max_count:
break
return out
@classmethod
def _prepare_exec_items(cls, path: str, argv_items: List[str], env_items: List[str]) -> Tuple[List[str], List[str]]:
normalized_path = cls._normalize_guest_path(path)
prepared_argv: List[str] = []
for item in argv_items[:EXEC_MAX_ARGS]:
value = cls._truncate_item_text(item)
if value:
prepared_argv.append(value)
if not prepared_argv:
prepared_argv = [cls._truncate_item_text(normalized_path)]
elif prepared_argv[0] == "":
prepared_argv[0] = cls._truncate_item_text(normalized_path)
prepared_env: List[str] = []
for item in env_items[:EXEC_MAX_ENVS]:
value = cls._truncate_item_text(item)
if value:
prepared_env.append(value)
return prepared_argv[:EXEC_MAX_ARGS], prepared_env[:EXEC_MAX_ENVS]
@classmethod
def _build_child_exec_items(cls, guest_path: str, argv_line: str, env_line: str) -> Tuple[List[str], List[str]]:
argv_items = [guest_path]
argv_items.extend(cls._parse_whitespace_items(argv_line or "", EXEC_MAX_ARGS - 1))
env_items = cls._parse_env_items(env_line or "", EXEC_MAX_ENVS)
return cls._prepare_exec_items(guest_path, argv_items, env_items)
def _copy_proc_item_to_guest(self, uc: Uc, item: Optional[str], out_ptr: int, out_size: int) -> int:
if out_ptr == 0 or out_size == 0 or item is None:
return 0
max_out = int(min(int(out_size), EXEC_ITEM_MAX))
if max_out <= 0:
return 0
encoded = self._truncate_item_text(item, max_out + 1).encode("utf-8", errors="replace")
if len(encoded) >= max_out:
encoded = encoded[: max_out - 1]
return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0
@staticmethod
def _signal_from_vector(vector: int) -> int:
if vector in (0, 16, 19):
return 8
if vector == 6:
return 4
if vector == 3:
return 5
if vector in (10, 11, 12, 13, 14, 17):
return 11
return 6
@staticmethod
def _encode_signal_status(signal: int, vector: int, error_code: int) -> int:
return u64(
EXEC_STATUS_SIGNAL_FLAG
| (int(signal) & 0xFF)
| ((int(vector) & 0xFF) << 8)
| ((int(error_code) & 0xFFFF) << 16)
)
def _status_from_uc_error(self, uc: Uc, exc: UcError) -> int:
errno = int(getattr(exc, "errno", 0))
vector = 13
error_code = 0
if errno in (UC_ERR_READ_UNMAPPED, UC_ERR_WRITE_UNMAPPED, UC_ERR_FETCH_UNMAPPED):
vector = 14
if errno == UC_ERR_WRITE_UNMAPPED:
error_code = 0x2
elif errno == UC_ERR_FETCH_UNMAPPED:
error_code = 0x10
elif errno in (UC_ERR_READ_PROT, UC_ERR_WRITE_PROT, UC_ERR_FETCH_PROT):
vector = 14
error_code = 0x1
if errno == UC_ERR_WRITE_PROT:
error_code |= 0x2
elif errno == UC_ERR_FETCH_PROT:
error_code |= 0x10
elif errno == UC_ERR_INSN_INVALID:
vector = 6
error_code = 0
rip = 0
try:
rip = self._reg_read(uc, UC_X86_REG_RIP)
except Exception:
rip = 0
signal = self._signal_from_vector(vector)
self.state.set_proc_fault(self.pid, signal, vector, error_code, rip)
return self._encode_signal_status(signal, vector, error_code)
def _guest_to_host(self, guest_path: str, *, must_exist: bool) -> Optional[Path]: def _guest_to_host(self, guest_path: str, *, must_exist: bool) -> Optional[Path]:
norm = self._normalize_guest_path(guest_path) norm = self._normalize_guest_path(guest_path)
if norm == "/": if norm == "/":

View File

@@ -4,7 +4,7 @@ import collections
import threading import threading
import time import time
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Deque, Dict, Optional, Tuple from typing import Deque, Dict, List, Optional, Tuple
from .constants import u64 from .constants import u64
@@ -44,6 +44,12 @@ class SharedKernelState:
proc_current_pid: int = 0 proc_current_pid: int = 0
proc_parents: Dict[int, int] = field(default_factory=dict) proc_parents: Dict[int, int] = field(default_factory=dict)
proc_status: Dict[int, Optional[int]] = field(default_factory=dict) proc_status: Dict[int, Optional[int]] = field(default_factory=dict)
proc_argv: Dict[int, List[str]] = field(default_factory=dict)
proc_env: Dict[int, List[str]] = field(default_factory=dict)
proc_last_signal: Dict[int, int] = field(default_factory=dict)
proc_fault_vector: Dict[int, int] = field(default_factory=dict)
proc_fault_error: Dict[int, int] = field(default_factory=dict)
proc_fault_rip: Dict[int, int] = field(default_factory=dict)
def timer_ticks(self) -> int: def timer_ticks(self) -> int:
return (time.monotonic_ns() - self.start_ns) // 1_000_000 return (time.monotonic_ns() - self.start_ns) // 1_000_000
@@ -101,6 +107,12 @@ class SharedKernelState:
self.proc_parents[pid] = int(ppid) self.proc_parents[pid] = int(ppid)
self.proc_status[pid] = None self.proc_status[pid] = None
self.proc_argv[pid] = []
self.proc_env[pid] = []
self.proc_last_signal[pid] = 0
self.proc_fault_vector[pid] = 0
self.proc_fault_error[pid] = 0
self.proc_fault_rip[pid] = 0
return pid return pid
def set_current_pid(self, pid: int) -> None: def set_current_pid(self, pid: int) -> None:
@@ -128,4 +140,64 @@ class SharedKernelState:
if status is None: if status is None:
return 0, 0 return 0, 0
return 1, int(status) return 1, int(status)
def set_proc_cmdline(self, pid: int, argv: List[str], env: List[str]) -> None:
if pid <= 0:
return
with self.proc_lock:
if pid not in self.proc_status:
return
self.proc_argv[pid] = [str(item) for item in argv]
self.proc_env[pid] = [str(item) for item in env]
def set_proc_fault(self, pid: int, signal: int, vector: int, error_code: int, rip: int) -> None:
if pid <= 0:
return
with self.proc_lock:
if pid not in self.proc_status:
return
self.proc_last_signal[pid] = int(u64(signal))
self.proc_fault_vector[pid] = int(u64(vector))
self.proc_fault_error[pid] = int(u64(error_code))
self.proc_fault_rip[pid] = int(u64(rip))
def proc_argc(self, pid: int) -> int:
with self.proc_lock:
return len(self.proc_argv.get(int(pid), []))
def proc_argv_item(self, pid: int, index: int) -> Optional[str]:
with self.proc_lock:
values = self.proc_argv.get(int(pid), [])
if index < 0 or index >= len(values):
return None
return values[index]
def proc_envc(self, pid: int) -> int:
with self.proc_lock:
return len(self.proc_env.get(int(pid), []))
def proc_env_item(self, pid: int, index: int) -> Optional[str]:
with self.proc_lock:
values = self.proc_env.get(int(pid), [])
if index < 0 or index >= len(values):
return None
return values[index]
def proc_signal(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_last_signal.get(int(pid), 0))
def proc_fault_vector_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_fault_vector.get(int(pid), 0))
def proc_fault_error_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_fault_error.get(int(pid), 0))
def proc_fault_rip_value(self, pid: int) -> int:
with self.proc_lock:
return int(self.proc_fault_rip.get(int(pid), 0))