mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
ABI
This commit is contained in:
@@ -361,7 +361,7 @@ set(RAMDISK_SYSTEM_APPS)
|
||||
set(RAMDISK_ROOT_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
|
||||
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm
|
||||
)
|
||||
|
||||
61
cleonos/c/apps/args_main.c
Normal file
61
cleonos/c/apps/args_main.c
Normal 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;
|
||||
}
|
||||
@@ -1,9 +1,28 @@
|
||||
#include "cmd_runtime.h"
|
||||
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];
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
@@ -13,7 +32,11 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
|
||||
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) {
|
||||
ush_writeln("exec: request failed");
|
||||
@@ -25,7 +48,16 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
static int ush_cmd_help(void) {
|
||||
ush_writeln("commands:");
|
||||
ush_writeln(" help");
|
||||
ush_writeln(" args [a b c] (print argc/argv/envp)");
|
||||
ush_writeln(" ls [-l] [-R] [path]");
|
||||
ush_writeln(" cat [file] (reads pipeline input when file omitted)");
|
||||
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(" pwd");
|
||||
ush_writeln(" cd [dir]");
|
||||
ush_writeln(" exec|run <path|name>");
|
||||
ush_writeln(" exec|run <path|name> [args...]");
|
||||
ush_writeln(" clear");
|
||||
ush_writeln(" ansi / ansitest / color");
|
||||
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(" rm <path> (/temp only)");
|
||||
ush_writeln(" pid");
|
||||
ush_writeln(" spawn <path|name>");
|
||||
ush_writeln(" spawn <path|name> [args...]");
|
||||
ush_writeln(" wait <pid>");
|
||||
ush_writeln(" sleep <ticks>");
|
||||
ush_writeln(" yield");
|
||||
|
||||
@@ -127,6 +127,7 @@ static int ush_split_two_args(const char *arg,
|
||||
static int ush_cmd_help(void) {
|
||||
ush_writeln("commands:");
|
||||
ush_writeln(" help");
|
||||
ush_writeln(" args [a b c] (print argc/argv/envp)");
|
||||
ush_writeln(" ls [-l] [-R] [path]");
|
||||
ush_writeln(" cat [file] (reads pipeline input when file omitted)");
|
||||
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(" pwd");
|
||||
ush_writeln(" cd [dir]");
|
||||
ush_writeln(" exec|run <path|name>");
|
||||
ush_writeln(" exec|run <path|name> [args...]");
|
||||
ush_writeln(" clear");
|
||||
ush_writeln(" ansi / ansitest / color");
|
||||
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(" rm <path> (/temp only)");
|
||||
ush_writeln(" pid");
|
||||
ush_writeln(" spawn <path|name>");
|
||||
ush_writeln(" spawn <path|name> [args...]");
|
||||
ush_writeln(" wait <pid>");
|
||||
ush_writeln(" sleep <ticks>");
|
||||
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) {
|
||||
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];
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
@@ -1498,7 +1518,11 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
|
||||
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) {
|
||||
ush_writeln("exec: request failed");
|
||||
@@ -1510,7 +1534,16 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1520,10 +1553,29 @@ static int ush_cmd_pid(void) {
|
||||
}
|
||||
|
||||
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];
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
@@ -1533,7 +1585,11 @@ static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
|
||||
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) {
|
||||
ush_writeln("spawn: request failed");
|
||||
@@ -1573,7 +1629,13 @@ static int ush_cmd_wait(const char *arg) {
|
||||
}
|
||||
|
||||
ush_writeln("wait: exited");
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
if (cmd == (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) {
|
||||
const char *canonical;
|
||||
char path[USH_PATH_MAX];
|
||||
char env_line[USH_PATH_MAX + USH_CMD_MAX + 32ULL];
|
||||
u64 status;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
if (status != 0ULL) {
|
||||
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) {
|
||||
*out_success = 0;
|
||||
|
||||
@@ -1,9 +1,28 @@
|
||||
#include "cmd_runtime.h"
|
||||
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];
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
@@ -13,7 +32,11 @@ static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
|
||||
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) {
|
||||
ush_writeln("spawn: request failed");
|
||||
|
||||
@@ -27,7 +27,13 @@ static int ush_cmd_wait(const char *arg) {
|
||||
}
|
||||
|
||||
ush_writeln("wait: exited");
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,16 @@ typedef unsigned long long usize;
|
||||
#define CLEONOS_SYSCALL_AUDIO_AVAILABLE 48ULL
|
||||
#define CLEONOS_SYSCALL_AUDIO_PLAY_TONE 49ULL
|
||||
#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_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_read(const char *path, char *out_buffer, u64 buffer_size);
|
||||
u64 cleonos_sys_exec_path(const char *path);
|
||||
u64 cleonos_sys_exec_pathv(const char *path, const char *argv_line, const char *env_line);
|
||||
u64 cleonos_sys_exec_request_count(void);
|
||||
u64 cleonos_sys_exec_success_count(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_getpid(void);
|
||||
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_exit(u64 status);
|
||||
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_play_tone(u64 hz, u64 ticks);
|
||||
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
|
||||
|
||||
@@ -1,12 +1,48 @@
|
||||
#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) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ u64 cleonos_sys_exec_path(const char *path) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
.global clks_exec_call_on_stack_x86_64
|
||||
.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:
|
||||
mov r11, rsp
|
||||
@@ -16,4 +18,12 @@ clks_exec_call_on_stack_x86_64:
|
||||
ret
|
||||
|
||||
.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
|
||||
|
||||
@@ -5,11 +5,27 @@
|
||||
|
||||
void clks_exec_init(void);
|
||||
clks_bool clks_exec_run_path(const char *path, u64 *out_status);
|
||||
clks_bool clks_exec_run_pathv(const char *path, const char *argv_line, const char *env_line, u64 *out_status);
|
||||
clks_bool clks_exec_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);
|
||||
clks_bool clks_exec_request_exit(u64 status);
|
||||
u64 clks_exec_current_pid(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_yield(void);
|
||||
void clks_exec_tick(u64 tick);
|
||||
|
||||
@@ -54,6 +54,16 @@
|
||||
#define CLKS_SYSCALL_AUDIO_AVAILABLE 48ULL
|
||||
#define CLKS_SYSCALL_AUDIO_PLAY_TONE 49ULL
|
||||
#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);
|
||||
u64 clks_syscall_dispatch(void *frame_ptr);
|
||||
|
||||
@@ -16,6 +16,12 @@ typedef u64 (*clks_exec_entry_fn)(void);
|
||||
#define CLKS_EXEC_MAX_PROCS 64U
|
||||
#define CLKS_EXEC_MAX_DEPTH 16U
|
||||
#define CLKS_EXEC_PATH_MAX 192U
|
||||
#define CLKS_EXEC_ARG_LINE_MAX 256U
|
||||
#define CLKS_EXEC_ENV_LINE_MAX 512U
|
||||
#define CLKS_EXEC_MAX_ARGS 24U
|
||||
#define CLKS_EXEC_MAX_ENVS 24U
|
||||
#define CLKS_EXEC_ITEM_MAX 128U
|
||||
#define CLKS_EXEC_STATUS_SIGNAL_FLAG (1ULL << 63)
|
||||
|
||||
enum clks_exec_proc_state {
|
||||
CLKS_EXEC_PROC_UNUSED = 0,
|
||||
@@ -34,10 +40,21 @@ struct clks_exec_proc_record {
|
||||
u64 exit_status;
|
||||
u32 tty_index;
|
||||
char path[CLKS_EXEC_PATH_MAX];
|
||||
char argv_line[CLKS_EXEC_ARG_LINE_MAX];
|
||||
char env_line[CLKS_EXEC_ENV_LINE_MAX];
|
||||
u32 argc;
|
||||
u32 envc;
|
||||
char argv_items[CLKS_EXEC_MAX_ARGS][CLKS_EXEC_ITEM_MAX];
|
||||
char env_items[CLKS_EXEC_MAX_ENVS][CLKS_EXEC_ITEM_MAX];
|
||||
u64 last_signal;
|
||||
u64 last_fault_vector;
|
||||
u64 last_fault_error;
|
||||
u64 last_fault_rip;
|
||||
};
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
extern u64 clks_exec_call_on_stack_x86_64(void *entry_ptr, void *stack_top);
|
||||
extern void clks_exec_abort_to_caller_x86_64(void);
|
||||
#endif
|
||||
|
||||
static u64 clks_exec_requests = 0ULL;
|
||||
@@ -50,6 +67,8 @@ 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 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 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';
|
||||
}
|
||||
|
||||
static void clks_exec_copy_line(char *dst, usize dst_size, const char *src) {
|
||||
usize i = 0U;
|
||||
|
||||
if (dst == CLKS_NULL || dst_size == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == CLKS_NULL) {
|
||||
dst[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
while (src[i] != '\0' && i + 1U < dst_size) {
|
||||
dst[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static void clks_exec_clear_items(char items[][CLKS_EXEC_ITEM_MAX], u32 max_count) {
|
||||
u32 i;
|
||||
|
||||
for (i = 0U; i < max_count; i++) {
|
||||
items[i][0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static u32 clks_exec_parse_whitespace_items(const char *line,
|
||||
char items[][CLKS_EXEC_ITEM_MAX],
|
||||
u32 max_count) {
|
||||
u32 count = 0U;
|
||||
usize i = 0U;
|
||||
|
||||
if (line == CLKS_NULL || items == CLKS_NULL || max_count == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
while (line[i] != '\0') {
|
||||
usize p = 0U;
|
||||
|
||||
while (line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '\n') {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (line[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (count >= max_count) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (line[i] != '\0' &&
|
||||
line[i] != ' ' &&
|
||||
line[i] != '\t' &&
|
||||
line[i] != '\r' &&
|
||||
line[i] != '\n') {
|
||||
if (p + 1U < CLKS_EXEC_ITEM_MAX) {
|
||||
items[count][p++] = line[i];
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
items[count][p] = '\0';
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static u32 clks_exec_parse_env_items(const char *line,
|
||||
char items[][CLKS_EXEC_ITEM_MAX],
|
||||
u32 max_count) {
|
||||
u32 count = 0U;
|
||||
usize i = 0U;
|
||||
|
||||
if (line == CLKS_NULL || items == CLKS_NULL || max_count == 0U) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
while (line[i] != '\0') {
|
||||
usize p = 0U;
|
||||
usize end_trim = 0U;
|
||||
|
||||
while (line[i] == ' ' || line[i] == '\t' || line[i] == ';' || line[i] == '\r' || line[i] == '\n') {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (line[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (count >= max_count) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (line[i] != '\0' && line[i] != ';' && line[i] != '\r' && line[i] != '\n') {
|
||||
if (p + 1U < CLKS_EXEC_ITEM_MAX) {
|
||||
items[count][p++] = line[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
while (p > 0U && (items[count][p - 1U] == ' ' || items[count][p - 1U] == '\t')) {
|
||||
p--;
|
||||
}
|
||||
|
||||
end_trim = p;
|
||||
items[count][end_trim] = '\0';
|
||||
|
||||
if (end_trim > 0U) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64 clks_exec_signal_from_vector(u64 vector) {
|
||||
switch (vector) {
|
||||
case 0ULL:
|
||||
case 16ULL:
|
||||
case 19ULL:
|
||||
return 8ULL;
|
||||
case 6ULL:
|
||||
return 4ULL;
|
||||
case 3ULL:
|
||||
return 5ULL;
|
||||
case 14ULL:
|
||||
case 13ULL:
|
||||
case 12ULL:
|
||||
case 11ULL:
|
||||
case 10ULL:
|
||||
case 17ULL:
|
||||
return 11ULL;
|
||||
default:
|
||||
return 6ULL;
|
||||
}
|
||||
}
|
||||
|
||||
static u64 clks_exec_encode_signal_status(u64 signal, u64 vector, u64 error_code) {
|
||||
return CLKS_EXEC_STATUS_SIGNAL_FLAG |
|
||||
(signal & 0xFFULL) |
|
||||
((vector & 0xFFULL) << 8) |
|
||||
((error_code & 0xFFFFULL) << 16);
|
||||
}
|
||||
|
||||
static i32 clks_exec_proc_find_slot_by_pid(u64 pid) {
|
||||
u32 i;
|
||||
|
||||
@@ -225,6 +393,8 @@ static u64 clks_exec_alloc_pid(void) {
|
||||
static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot,
|
||||
u64 pid,
|
||||
const char *path,
|
||||
const char *argv_line,
|
||||
const char *env_line,
|
||||
enum clks_exec_proc_state state) {
|
||||
struct clks_exec_proc_record *proc;
|
||||
|
||||
@@ -244,10 +414,36 @@ static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot,
|
||||
proc->exit_status = (u64)-1;
|
||||
proc->tty_index = clks_tty_active();
|
||||
clks_exec_copy_path(proc->path, sizeof(proc->path), path);
|
||||
clks_exec_copy_line(proc->argv_line, sizeof(proc->argv_line), argv_line);
|
||||
clks_exec_copy_line(proc->env_line, sizeof(proc->env_line), env_line);
|
||||
clks_exec_clear_items(proc->argv_items, CLKS_EXEC_MAX_ARGS);
|
||||
clks_exec_clear_items(proc->env_items, CLKS_EXEC_MAX_ENVS);
|
||||
proc->argc = 0U;
|
||||
proc->envc = 0U;
|
||||
proc->last_signal = 0ULL;
|
||||
proc->last_fault_vector = 0ULL;
|
||||
proc->last_fault_error = 0ULL;
|
||||
proc->last_fault_rip = 0ULL;
|
||||
|
||||
if (proc->argc < CLKS_EXEC_MAX_ARGS) {
|
||||
clks_exec_copy_path(proc->argv_items[proc->argc], CLKS_EXEC_ITEM_MAX, path);
|
||||
proc->argc++;
|
||||
}
|
||||
|
||||
if (proc->argv_line[0] != '\0' && proc->argc < CLKS_EXEC_MAX_ARGS) {
|
||||
proc->argc += clks_exec_parse_whitespace_items(proc->argv_line,
|
||||
&proc->argv_items[proc->argc],
|
||||
(u32)(CLKS_EXEC_MAX_ARGS - proc->argc));
|
||||
}
|
||||
|
||||
if (proc->env_line[0] != '\0') {
|
||||
proc->envc = clks_exec_parse_env_items(proc->env_line, proc->env_items, CLKS_EXEC_MAX_ENVS);
|
||||
}
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
static 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) {
|
||||
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_top;
|
||||
u64 unwind_slot;
|
||||
|
||||
if (stack_base == CLKS_NULL) {
|
||||
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);
|
||||
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);
|
||||
clks_exec_unwind_slot_valid_stack[depth_index] = CLKS_FALSE;
|
||||
clks_exec_unwind_slot_stack[depth_index] = 0ULL;
|
||||
clks_kfree(stack_base);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
#else
|
||||
(void)depth_index;
|
||||
*out_ret = ((clks_exec_entry_fn)entry_ptr)();
|
||||
return CLKS_TRUE;
|
||||
#endif
|
||||
@@ -364,7 +567,7 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) {
|
||||
clks_exec_running_depth++;
|
||||
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", proc->path);
|
||||
goto fail;
|
||||
@@ -450,7 +653,11 @@ static clks_bool clks_exec_dispatch_pending_once(void) {
|
||||
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;
|
||||
u64 pid;
|
||||
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();
|
||||
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) {
|
||||
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_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_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_exec_log_info_serial("PATH EXEC FRAMEWORK ONLINE");
|
||||
}
|
||||
|
||||
clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
|
||||
return clks_exec_run_path_internal(path, 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;
|
||||
u64 pid;
|
||||
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();
|
||||
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) {
|
||||
return CLKS_FALSE;
|
||||
@@ -559,6 +772,10 @@ clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) {
|
||||
return clks_exec_spawn_pathv(path, CLKS_NULL, CLKS_NULL, out_pid);
|
||||
}
|
||||
|
||||
u64 clks_exec_wait_pid(u64 pid, u64 *out_status) {
|
||||
i32 slot;
|
||||
struct clks_exec_proc_record *proc;
|
||||
@@ -650,6 +867,159 @@ u32 clks_exec_current_tty(void) {
|
||||
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 start = clks_interrupts_timer_ticks();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <clks/compiler.h>
|
||||
#include <clks/cpu.h>
|
||||
#include <clks/exec.h>
|
||||
#include <clks/interrupts.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/keyboard.h>
|
||||
@@ -250,6 +251,15 @@ void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#define CLKS_SYSCALL_TTY_MAX_LEN 512U
|
||||
#define CLKS_SYSCALL_FS_IO_MAX_LEN 65536U
|
||||
#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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
const char *src = (const char *)arg0;
|
||||
u64 len = arg1;
|
||||
@@ -218,6 +234,31 @@ static u64 clks_syscall_exec_path(u64 arg0) {
|
||||
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) {
|
||||
return clks_exec_current_pid();
|
||||
}
|
||||
@@ -237,6 +278,31 @@ static u64 clks_syscall_spawn_path(u64 arg0) {
|
||||
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) {
|
||||
u64 status = (u64)-1;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
case CLKS_SYSCALL_EXEC_PATH:
|
||||
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:
|
||||
return clks_exec_request_count();
|
||||
case CLKS_SYSCALL_EXEC_SUCCESS:
|
||||
@@ -587,8 +703,26 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
|
||||
return clks_syscall_getpid();
|
||||
case CLKS_SYSCALL_SPAWN_PATH:
|
||||
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:
|
||||
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:
|
||||
return clks_syscall_exit(frame->rbx);
|
||||
case CLKS_SYSCALL_SLEEP_TICKS:
|
||||
|
||||
@@ -8,16 +8,20 @@
|
||||
## Implementation
|
||||
- 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.
|
||||
- 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.
|
||||
- Refactored Wine codebase from single-file implementation into modular structure for CLI, ELF loader, syscall bridge, and runtime helpers.
|
||||
|
||||
## Acceptance Criteria
|
||||
- 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:
|
||||
- `clks/include/clks/syscall.h`
|
||||
- `cleonos/c/include/cleonos_syscall.h`
|
||||
- `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
|
||||
- `make userapps`
|
||||
|
||||
@@ -36,6 +36,14 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
- 失败时多数接口返回 `0xFFFFFFFFFFFFFFFF`(即 `u64` 的 `-1`)。
|
||||
- 部分接口失败返回 `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. 当前实现中的长度/路径限制
|
||||
|
||||
以下限制由内核 `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` 树下路径。
|
||||
|
||||
## 4. Syscall 列表(0~50)
|
||||
## 4. Syscall 列表(0~60)
|
||||
|
||||
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
|
||||
|
||||
@@ -371,6 +379,73 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
||||
- 返回:当前实现固定返回 `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. 用户态封装函数
|
||||
|
||||
用户态封装位于:
|
||||
@@ -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_log_journal_count()` / `cleonos_sys_log_journal_read()`
|
||||
- `cleonos_sys_exec_path()`
|
||||
- `cleonos_sys_exec_pathv()`
|
||||
- `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_spawn_pathv()`
|
||||
- `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_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. 开发注意事项
|
||||
|
||||
- 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。
|
||||
- `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`。
|
||||
- `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`。
|
||||
|
||||
@@ -37,15 +37,31 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
|
||||
## 支持
|
||||
|
||||
- ELF64 (x86_64) PT_LOAD 段装载
|
||||
- CLeonOS `int 0x80` syscall 0..45
|
||||
- CLeonOS `int 0x80` syscall 0..60
|
||||
- TTY 输出与键盘输入队列
|
||||
- rootfs 文件/目录访问(`FS_*`)
|
||||
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
||||
- `EXEC_PATH` 递归执行 ELF(带深度限制)
|
||||
- 进程生命周期 syscall(`GETPID/SPAWN_PATH/WAITPID/EXIT/SLEEP_TICKS/YIELD`)
|
||||
- `EXEC_PATH/EXEC_PATHV` 执行 ELF(带深度限制)
|
||||
- `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`:关闭输入线程
|
||||
- `--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 位
|
||||
|
||||
BIN
wine/__pycache__/cleonos_wine.cpython-313.pyc
Normal file
BIN
wine/__pycache__/cleonos_wine.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -56,6 +56,19 @@ SYS_SLEEP_TICKS = 44
|
||||
SYS_YIELD = 45
|
||||
SYS_SHUTDOWN = 46
|
||||
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:
|
||||
|
||||
@@ -7,12 +7,22 @@ try:
|
||||
from unicorn import UC_ARCH_X86, UC_MODE_64
|
||||
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_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 (
|
||||
UC_X86_REG_RAX,
|
||||
UC_X86_REG_RBX,
|
||||
UC_X86_REG_RCX,
|
||||
UC_X86_REG_RDX,
|
||||
UC_X86_REG_RBP,
|
||||
UC_X86_REG_RIP,
|
||||
UC_X86_REG_RSP,
|
||||
)
|
||||
except Exception as exc:
|
||||
@@ -32,10 +42,18 @@ __all__ = [
|
||||
"UC_PROT_EXEC",
|
||||
"UC_PROT_READ",
|
||||
"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_RBX",
|
||||
"UC_X86_REG_RCX",
|
||||
"UC_X86_REG_RDX",
|
||||
"UC_X86_REG_RBP",
|
||||
"UC_X86_REG_RIP",
|
||||
"UC_X86_REG_RSP",
|
||||
]
|
||||
@@ -14,15 +14,28 @@ from .constants import (
|
||||
MAX_CSTR,
|
||||
MAX_IO_READ,
|
||||
PAGE_SIZE,
|
||||
SYS_AUDIO_AVAILABLE,
|
||||
SYS_AUDIO_PLAY_TONE,
|
||||
SYS_AUDIO_STOP,
|
||||
SYS_CONTEXT_SWITCHES,
|
||||
SYS_CUR_TASK,
|
||||
SYS_EXEC_PATH,
|
||||
SYS_EXEC_PATHV,
|
||||
SYS_EXEC_REQUESTS,
|
||||
SYS_EXEC_SUCCESS,
|
||||
SYS_EXIT,
|
||||
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_SPAWN_PATH,
|
||||
SYS_SPAWN_PATHV,
|
||||
SYS_WAITPID,
|
||||
SYS_YIELD,
|
||||
SYS_SHUTDOWN,
|
||||
@@ -72,6 +85,13 @@ from .platform import (
|
||||
Uc,
|
||||
UcError,
|
||||
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_INTR,
|
||||
UC_MODE_64,
|
||||
@@ -85,6 +105,7 @@ from .platform import (
|
||||
UC_X86_REG_RCX,
|
||||
UC_X86_REG_RDX,
|
||||
UC_X86_REG_RSP,
|
||||
UC_X86_REG_RIP,
|
||||
)
|
||||
from .state import SharedKernelState
|
||||
|
||||
@@ -103,6 +124,15 @@ class ELFImage:
|
||||
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:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -118,6 +148,8 @@ class CLeonOSWineNative:
|
||||
top_level: bool = True,
|
||||
pid: int = 0,
|
||||
ppid: int = 0,
|
||||
argv_items: Optional[List[str]] = None,
|
||||
env_items: Optional[List[str]] = None,
|
||||
) -> None:
|
||||
self.elf_path = elf_path
|
||||
self.rootfs = rootfs
|
||||
@@ -130,6 +162,8 @@ class CLeonOSWineNative:
|
||||
self.top_level = top_level
|
||||
self.pid = int(pid)
|
||||
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_status = 0
|
||||
|
||||
@@ -142,12 +176,17 @@ class CLeonOSWineNative:
|
||||
self._ret_sentinel = 0x00007FFF10000000
|
||||
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]:
|
||||
if self.pid == 0:
|
||||
self.pid = self.state.alloc_pid(self.ppid)
|
||||
|
||||
prev_pid = self.state.get_current_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)
|
||||
self._install_hooks(uc)
|
||||
@@ -158,27 +197,31 @@ class CLeonOSWineNative:
|
||||
self._input_pump = InputPump(self.state)
|
||||
self._input_pump.start()
|
||||
|
||||
run_failed = False
|
||||
interrupted = False
|
||||
runtime_fault_status: Optional[int] = None
|
||||
|
||||
try:
|
||||
uc.emu_start(self.image.entry, 0)
|
||||
except KeyboardInterrupt:
|
||||
run_failed = True
|
||||
interrupted = True
|
||||
if self.top_level:
|
||||
print("\n[WINE] interrupted by user", file=sys.stderr)
|
||||
except UcError as exc:
|
||||
run_failed = True
|
||||
runtime_fault_status = self._status_from_uc_error(uc, exc)
|
||||
if self.verbose or self.top_level:
|
||||
print(f"[WINE][ERROR] runtime crashed: {exc}", file=sys.stderr)
|
||||
finally:
|
||||
if self.top_level and self._input_pump is not None:
|
||||
self._input_pump.stop()
|
||||
|
||||
if run_failed:
|
||||
if interrupted:
|
||||
self.state.mark_exited(self.pid, u64_neg1())
|
||||
self.state.set_current_pid(prev_pid)
|
||||
return None
|
||||
|
||||
if runtime_fault_status is not None:
|
||||
self.exit_code = runtime_fault_status
|
||||
|
||||
if self.exit_code is None:
|
||||
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)
|
||||
if sid == SYS_EXEC_PATH:
|
||||
return self._exec_path(uc, arg0)
|
||||
if sid == SYS_EXEC_PATHV:
|
||||
return self._exec_pathv(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_SPAWN_PATH:
|
||||
return self._spawn_path(uc, arg0)
|
||||
if sid == SYS_SPAWN_PATHV:
|
||||
return self._spawn_pathv(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_WAITPID:
|
||||
return self._wait_pid(uc, arg0, arg1)
|
||||
if sid == SYS_GETPID:
|
||||
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:
|
||||
return self._request_exit(uc, arg0)
|
||||
if sid == SYS_SLEEP_TICKS:
|
||||
return self._sleep_ticks(arg0)
|
||||
if sid == SYS_YIELD:
|
||||
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:
|
||||
self._host_write("\n[WINE] shutdown requested by guest\n")
|
||||
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
|
||||
|
||||
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:
|
||||
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:
|
||||
path = self._read_guest_cstring(uc, path_ptr)
|
||||
def _spawn_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=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)
|
||||
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)
|
||||
|
||||
self.state.exec_requests = u64(self.state.exec_requests + 1)
|
||||
@@ -699,6 +784,9 @@ class CLeonOSWineNative:
|
||||
|
||||
parent_pid = self.state.get_current_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(
|
||||
elf_path=host_path,
|
||||
@@ -712,6 +800,8 @@ class CLeonOSWineNative:
|
||||
top_level=False,
|
||||
pid=child_pid,
|
||||
ppid=parent_pid,
|
||||
argv_items=argv_items,
|
||||
env_items=env_items,
|
||||
)
|
||||
child_ret = child.run()
|
||||
|
||||
@@ -728,7 +818,41 @@ class CLeonOSWineNative:
|
||||
if return_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:
|
||||
wait_ret, status = self.state.wait_pid(int(pid))
|
||||
@@ -761,6 +885,157 @@ class CLeonOSWineNative:
|
||||
time.sleep(0)
|
||||
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]:
|
||||
norm = self._normalize_guest_path(guest_path)
|
||||
if norm == "/":
|
||||
|
||||
@@ -4,7 +4,7 @@ import collections
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Deque, Dict, Optional, Tuple
|
||||
from typing import Deque, Dict, List, Optional, Tuple
|
||||
|
||||
from .constants import u64
|
||||
|
||||
@@ -44,6 +44,12 @@ class SharedKernelState:
|
||||
proc_current_pid: int = 0
|
||||
proc_parents: Dict[int, 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:
|
||||
return (time.monotonic_ns() - self.start_ns) // 1_000_000
|
||||
@@ -101,6 +107,12 @@ class SharedKernelState:
|
||||
|
||||
self.proc_parents[pid] = int(ppid)
|
||||
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
|
||||
|
||||
def set_current_pid(self, pid: int) -> None:
|
||||
@@ -129,3 +141,63 @@ class SharedKernelState:
|
||||
return 0, 0
|
||||
|
||||
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))
|
||||
|
||||
Reference in New Issue
Block a user