mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 18:44:01 +00:00
Stage 27
This commit is contained in:
@@ -127,6 +127,12 @@ static int ush_cmd_help(void) {
|
|||||||
ush_writeln(" cp <src> <dst> (dst /temp only)");
|
ush_writeln(" cp <src> <dst> (dst /temp only)");
|
||||||
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(" spawn <path|name>");
|
||||||
|
ush_writeln(" wait <pid>");
|
||||||
|
ush_writeln(" sleep <ticks>");
|
||||||
|
ush_writeln(" yield");
|
||||||
|
ush_writeln(" exit [code]");
|
||||||
ush_writeln(" rusttest / panic / elfloader (kernel shell only)");
|
ush_writeln(" rusttest / panic / elfloader (kernel shell only)");
|
||||||
ush_writeln("edit keys: Left/Right, Home/End, Up/Down history");
|
ush_writeln("edit keys: Left/Right, Home/End, Up/Down history");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -283,6 +289,114 @@ static int ush_cmd_exec(const ush_state *sh, const char *arg) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ush_cmd_pid(void) {
|
||||||
|
ush_print_kv_hex("PID", cleonos_sys_getpid());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ush_cmd_spawn(const ush_state *sh, const char *arg) {
|
||||||
|
char path[USH_PATH_MAX];
|
||||||
|
u64 pid;
|
||||||
|
|
||||||
|
if (ush_resolve_exec_path(sh, arg, path, (u64)sizeof(path)) == 0) {
|
||||||
|
ush_writeln("spawn: invalid target");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ush_path_is_under_system(path) != 0) {
|
||||||
|
ush_writeln("spawn: /system/*.elf is kernel-mode (KELF), not user-exec");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = cleonos_sys_spawn_path(path);
|
||||||
|
|
||||||
|
if (pid == (u64)-1) {
|
||||||
|
ush_writeln("spawn: request failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ush_writeln("spawn: completed");
|
||||||
|
ush_print_kv_hex(" PID", pid);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ush_cmd_wait(const char *arg) {
|
||||||
|
u64 pid;
|
||||||
|
u64 status = (u64)-1;
|
||||||
|
u64 wait_ret;
|
||||||
|
|
||||||
|
if (arg == (const char *)0 || arg[0] == '\0') {
|
||||||
|
ush_writeln("wait: usage wait <pid>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ush_parse_u64_dec(arg, &pid) == 0) {
|
||||||
|
ush_writeln("wait: invalid pid");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_ret = cleonos_sys_wait_pid(pid, &status);
|
||||||
|
|
||||||
|
if (wait_ret == (u64)-1) {
|
||||||
|
ush_writeln("wait: pid not found");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_ret == 0ULL) {
|
||||||
|
ush_writeln("wait: still running");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ush_writeln("wait: exited");
|
||||||
|
ush_print_kv_hex(" STATUS", status);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ush_cmd_sleep(const char *arg) {
|
||||||
|
u64 ticks;
|
||||||
|
u64 elapsed;
|
||||||
|
|
||||||
|
if (arg == (const char *)0 || arg[0] == '\0') {
|
||||||
|
ush_writeln("sleep: usage sleep <ticks>");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ush_parse_u64_dec(arg, &ticks) == 0) {
|
||||||
|
ush_writeln("sleep: invalid ticks");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed = cleonos_sys_sleep_ticks(ticks);
|
||||||
|
ush_print_kv_hex("SLEPT_TICKS", elapsed);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ush_cmd_yield(void) {
|
||||||
|
ush_print_kv_hex("YIELD_TICK", cleonos_sys_yield());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ush_cmd_exit(ush_state *sh, const char *arg) {
|
||||||
|
u64 code = 0ULL;
|
||||||
|
|
||||||
|
if (sh == (ush_state *)0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg != (const char *)0 && arg[0] != '\0') {
|
||||||
|
if (ush_parse_u64_dec(arg, &code) == 0) {
|
||||||
|
ush_writeln("exit: usage exit [code]");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sh->exit_requested = 1;
|
||||||
|
sh->exit_code = code;
|
||||||
|
(void)cleonos_sys_exit(code);
|
||||||
|
ush_writeln("exit: shell stopping");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int ush_cmd_clear(void) {
|
static int ush_cmd_clear(void) {
|
||||||
u64 i;
|
u64 i;
|
||||||
|
|
||||||
@@ -352,6 +466,8 @@ static int ush_cmd_shstat(const ush_state *sh) {
|
|||||||
ush_print_kv_hex(" CMD_OK", sh->cmd_ok);
|
ush_print_kv_hex(" CMD_OK", sh->cmd_ok);
|
||||||
ush_print_kv_hex(" CMD_FAIL", sh->cmd_fail);
|
ush_print_kv_hex(" CMD_FAIL", sh->cmd_fail);
|
||||||
ush_print_kv_hex(" CMD_UNKNOWN", sh->cmd_unknown);
|
ush_print_kv_hex(" CMD_UNKNOWN", sh->cmd_unknown);
|
||||||
|
ush_print_kv_hex(" EXIT_REQUESTED", (sh->exit_requested != 0) ? 1ULL : 0ULL);
|
||||||
|
ush_print_kv_hex(" EXIT_CODE", sh->exit_code);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,6 +860,18 @@ void ush_execute_line(ush_state *sh, const char *line) {
|
|||||||
success = ush_cmd_cd(sh, arg);
|
success = ush_cmd_cd(sh, arg);
|
||||||
} else if (ush_streq(cmd, "exec") != 0 || ush_streq(cmd, "run") != 0) {
|
} else if (ush_streq(cmd, "exec") != 0 || ush_streq(cmd, "run") != 0) {
|
||||||
success = ush_cmd_exec(sh, arg);
|
success = ush_cmd_exec(sh, arg);
|
||||||
|
} else if (ush_streq(cmd, "pid") != 0) {
|
||||||
|
success = ush_cmd_pid();
|
||||||
|
} else if (ush_streq(cmd, "spawn") != 0) {
|
||||||
|
success = ush_cmd_spawn(sh, arg);
|
||||||
|
} else if (ush_streq(cmd, "wait") != 0) {
|
||||||
|
success = ush_cmd_wait(arg);
|
||||||
|
} else if (ush_streq(cmd, "sleep") != 0) {
|
||||||
|
success = ush_cmd_sleep(arg);
|
||||||
|
} else if (ush_streq(cmd, "yield") != 0) {
|
||||||
|
success = ush_cmd_yield();
|
||||||
|
} else if (ush_streq(cmd, "exit") != 0) {
|
||||||
|
success = ush_cmd_exit(sh, arg);
|
||||||
} else if (ush_streq(cmd, "clear") != 0 || ush_streq(cmd, "cls") != 0) {
|
} else if (ush_streq(cmd, "clear") != 0 || ush_streq(cmd, "cls") != 0) {
|
||||||
success = ush_cmd_clear();
|
success = ush_cmd_clear();
|
||||||
} else if (ush_streq(cmd, "memstat") != 0) {
|
} else if (ush_streq(cmd, "memstat") != 0) {
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ typedef struct ush_state {
|
|||||||
u64 cmd_ok;
|
u64 cmd_ok;
|
||||||
u64 cmd_fail;
|
u64 cmd_fail;
|
||||||
u64 cmd_unknown;
|
u64 cmd_unknown;
|
||||||
|
int exit_requested;
|
||||||
|
u64 exit_code;
|
||||||
} ush_state;
|
} ush_state;
|
||||||
|
|
||||||
void ush_init_state(ush_state *sh);
|
void ush_init_state(ush_state *sh);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ void ush_init_state(ush_state *sh) {
|
|||||||
sh->cmd_ok = 0ULL;
|
sh->cmd_ok = 0ULL;
|
||||||
sh->cmd_fail = 0ULL;
|
sh->cmd_fail = 0ULL;
|
||||||
sh->cmd_unknown = 0ULL;
|
sh->cmd_unknown = 0ULL;
|
||||||
|
sh->exit_requested = 0;
|
||||||
|
sh->exit_code = 0ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 ush_strlen(const char *str) {
|
u64 ush_strlen(const char *str) {
|
||||||
|
|||||||
@@ -14,5 +14,9 @@ int cleonos_app_main(void) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
ush_read_line(&sh, line, (u64)sizeof(line));
|
ush_read_line(&sh, line, (u64)sizeof(line));
|
||||||
ush_execute_line(&sh, line);
|
ush_execute_line(&sh, line);
|
||||||
|
|
||||||
|
if (sh.exit_requested != 0) {
|
||||||
|
return (int)(sh.exit_code & 0x7FFFFFFFULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,12 @@ typedef unsigned long long usize;
|
|||||||
#define CLEONOS_SYSCALL_KBD_POPPED 37ULL
|
#define CLEONOS_SYSCALL_KBD_POPPED 37ULL
|
||||||
#define CLEONOS_SYSCALL_KBD_DROPPED 38ULL
|
#define CLEONOS_SYSCALL_KBD_DROPPED 38ULL
|
||||||
#define CLEONOS_SYSCALL_KBD_HOTKEY_SWITCHES 39ULL
|
#define CLEONOS_SYSCALL_KBD_HOTKEY_SWITCHES 39ULL
|
||||||
|
#define CLEONOS_SYSCALL_GETPID 40ULL
|
||||||
|
#define CLEONOS_SYSCALL_SPAWN_PATH 41ULL
|
||||||
|
#define CLEONOS_SYSCALL_WAITPID 42ULL
|
||||||
|
#define CLEONOS_SYSCALL_EXIT 43ULL
|
||||||
|
#define CLEONOS_SYSCALL_SLEEP_TICKS 44ULL
|
||||||
|
#define CLEONOS_SYSCALL_YIELD 45ULL
|
||||||
|
|
||||||
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);
|
||||||
@@ -87,5 +93,11 @@ u64 cleonos_sys_kbd_pushed(void);
|
|||||||
u64 cleonos_sys_kbd_popped(void);
|
u64 cleonos_sys_kbd_popped(void);
|
||||||
u64 cleonos_sys_kbd_dropped(void);
|
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_spawn_path(const char *path);
|
||||||
|
u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status);
|
||||||
|
u64 cleonos_sys_exit(u64 status);
|
||||||
|
u64 cleonos_sys_sleep_ticks(u64 ticks);
|
||||||
|
u64 cleonos_sys_yield(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -168,3 +168,27 @@ u64 cleonos_sys_kbd_dropped(void) {
|
|||||||
u64 cleonos_sys_kbd_hotkey_switches(void) {
|
u64 cleonos_sys_kbd_hotkey_switches(void) {
|
||||||
return cleonos_syscall(CLEONOS_SYSCALL_KBD_HOTKEY_SWITCHES, 0ULL, 0ULL, 0ULL);
|
return cleonos_syscall(CLEONOS_SYSCALL_KBD_HOTKEY_SWITCHES, 0ULL, 0ULL, 0ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_getpid(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_GETPID, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_spawn_path(const char *path) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_SPAWN_PATH, (u64)path, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_wait_pid(u64 pid, u64 *out_status) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_WAITPID, pid, (u64)out_status, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_exit(u64 status) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_EXIT, status, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_sleep_ticks(u64 ticks) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_SLEEP_TICKS, ticks, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cleonos_sys_yield(void) {
|
||||||
|
return cleonos_syscall(CLEONOS_SYSCALL_YIELD, 0ULL, 0ULL, 0ULL);
|
||||||
|
}
|
||||||
@@ -5,9 +5,14 @@
|
|||||||
|
|
||||||
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_spawn_path(const char *path, 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);
|
||||||
|
u64 clks_exec_sleep_ticks(u64 ticks);
|
||||||
|
u64 clks_exec_yield(void);
|
||||||
u64 clks_exec_request_count(void);
|
u64 clks_exec_request_count(void);
|
||||||
u64 clks_exec_success_count(void);
|
u64 clks_exec_success_count(void);
|
||||||
clks_bool clks_exec_is_running(void);
|
clks_bool clks_exec_is_running(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,12 @@
|
|||||||
#define CLKS_SYSCALL_KBD_POPPED 37ULL
|
#define CLKS_SYSCALL_KBD_POPPED 37ULL
|
||||||
#define CLKS_SYSCALL_KBD_DROPPED 38ULL
|
#define CLKS_SYSCALL_KBD_DROPPED 38ULL
|
||||||
#define CLKS_SYSCALL_KBD_HOTKEY_SWITCHES 39ULL
|
#define CLKS_SYSCALL_KBD_HOTKEY_SWITCHES 39ULL
|
||||||
|
#define CLKS_SYSCALL_GETPID 40ULL
|
||||||
|
#define CLKS_SYSCALL_SPAWN_PATH 41ULL
|
||||||
|
#define CLKS_SYSCALL_WAITPID 42ULL
|
||||||
|
#define CLKS_SYSCALL_EXIT 43ULL
|
||||||
|
#define CLKS_SYSCALL_SLEEP_TICKS 44ULL
|
||||||
|
#define CLKS_SYSCALL_YIELD 45ULL
|
||||||
|
|
||||||
void clks_syscall_init(void);
|
void clks_syscall_init(void);
|
||||||
u64 clks_syscall_dispatch(void *frame_ptr);
|
u64 clks_syscall_dispatch(void *frame_ptr);
|
||||||
|
|||||||
@@ -1,13 +1,36 @@
|
|||||||
|
#include <clks/cpu.h>
|
||||||
#include <clks/elf64.h>
|
#include <clks/elf64.h>
|
||||||
#include <clks/exec.h>
|
#include <clks/exec.h>
|
||||||
#include <clks/fs.h>
|
#include <clks/fs.h>
|
||||||
#include <clks/heap.h>
|
#include <clks/heap.h>
|
||||||
|
#include <clks/interrupts.h>
|
||||||
#include <clks/log.h>
|
#include <clks/log.h>
|
||||||
|
#include <clks/string.h>
|
||||||
#include <clks/types.h>
|
#include <clks/types.h>
|
||||||
|
|
||||||
typedef u64 (*clks_exec_entry_fn)(void);
|
typedef u64 (*clks_exec_entry_fn)(void);
|
||||||
|
|
||||||
#define CLKS_EXEC_RUN_STACK_BYTES (64ULL * 1024ULL)
|
#define CLKS_EXEC_RUN_STACK_BYTES (64ULL * 1024ULL)
|
||||||
|
#define CLKS_EXEC_MAX_PROCS 64U
|
||||||
|
#define CLKS_EXEC_MAX_DEPTH 16U
|
||||||
|
#define CLKS_EXEC_PATH_MAX 192U
|
||||||
|
|
||||||
|
enum clks_exec_proc_state {
|
||||||
|
CLKS_EXEC_PROC_UNUSED = 0,
|
||||||
|
CLKS_EXEC_PROC_RUNNING = 1,
|
||||||
|
CLKS_EXEC_PROC_EXITED = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clks_exec_proc_record {
|
||||||
|
clks_bool used;
|
||||||
|
enum clks_exec_proc_state state;
|
||||||
|
u64 pid;
|
||||||
|
u64 ppid;
|
||||||
|
u64 started_tick;
|
||||||
|
u64 exited_tick;
|
||||||
|
u64 exit_status;
|
||||||
|
char path[CLKS_EXEC_PATH_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
#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);
|
||||||
@@ -17,6 +40,66 @@ static u64 clks_exec_requests = 0ULL;
|
|||||||
static u64 clks_exec_success = 0ULL;
|
static u64 clks_exec_success = 0ULL;
|
||||||
static u32 clks_exec_running_depth = 0U;
|
static u32 clks_exec_running_depth = 0U;
|
||||||
|
|
||||||
|
static struct clks_exec_proc_record clks_exec_proc_table[CLKS_EXEC_MAX_PROCS];
|
||||||
|
static u64 clks_exec_next_pid = 1ULL;
|
||||||
|
static u64 clks_exec_pid_stack[CLKS_EXEC_MAX_DEPTH];
|
||||||
|
static clks_bool clks_exec_exit_requested_stack[CLKS_EXEC_MAX_DEPTH];
|
||||||
|
static u64 clks_exec_exit_status_stack[CLKS_EXEC_MAX_DEPTH];
|
||||||
|
static u32 clks_exec_pid_stack_depth = 0U;
|
||||||
|
|
||||||
|
static void clks_exec_copy_path(char *dst, usize dst_size, const char *src) {
|
||||||
|
usize i = 0U;
|
||||||
|
|
||||||
|
if (dst == CLKS_NULL || src == CLKS_NULL || dst_size == 0U) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (src[i] != '\0' && i + 1U < dst_size) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static i32 clks_exec_proc_find_slot_by_pid(u64 pid) {
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) {
|
||||||
|
if (clks_exec_proc_table[i].used == CLKS_TRUE && clks_exec_proc_table[i].pid == pid) {
|
||||||
|
return (i32)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static i32 clks_exec_proc_alloc_slot(void) {
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) {
|
||||||
|
if (clks_exec_proc_table[i].used == CLKS_FALSE) {
|
||||||
|
return (i32)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0U; i < CLKS_EXEC_MAX_PROCS; i++) {
|
||||||
|
if (clks_exec_proc_table[i].state == CLKS_EXEC_PROC_EXITED) {
|
||||||
|
return (i32)i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static i32 clks_exec_current_depth_index(void) {
|
||||||
|
if (clks_exec_pid_stack_depth == 0U) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (i32)(clks_exec_pid_stack_depth - 1U);
|
||||||
|
}
|
||||||
|
|
||||||
static clks_bool clks_exec_invoke_entry(void *entry_ptr, u64 *out_ret) {
|
static clks_bool clks_exec_invoke_entry(void *entry_ptr, 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;
|
||||||
@@ -43,20 +126,20 @@ static clks_bool clks_exec_invoke_entry(void *entry_ptr, u64 *out_ret) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void clks_exec_init(void) {
|
static clks_bool clks_exec_run_path_internal(const char *path, u64 *out_status, u64 *out_pid) {
|
||||||
clks_exec_requests = 0ULL;
|
|
||||||
clks_exec_success = 0ULL;
|
|
||||||
clks_exec_running_depth = 0U;
|
|
||||||
clks_log(CLKS_LOG_INFO, "EXEC", "PATH EXEC FRAMEWORK ONLINE");
|
|
||||||
}
|
|
||||||
|
|
||||||
clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
|
|
||||||
const void *image;
|
const void *image;
|
||||||
u64 image_size = 0ULL;
|
u64 image_size = 0ULL;
|
||||||
struct clks_elf64_info info;
|
struct clks_elf64_info info;
|
||||||
struct clks_elf64_loaded_image loaded;
|
struct clks_elf64_loaded_image loaded;
|
||||||
|
clks_bool loaded_active = CLKS_FALSE;
|
||||||
void *entry_ptr;
|
void *entry_ptr;
|
||||||
u64 run_ret;
|
u64 run_ret = (u64)-1;
|
||||||
|
u64 pid = (u64)-1;
|
||||||
|
i32 slot;
|
||||||
|
i32 depth_index;
|
||||||
|
struct clks_exec_proc_record *proc;
|
||||||
|
|
||||||
|
clks_memset(&loaded, 0, sizeof(loaded));
|
||||||
|
|
||||||
clks_exec_requests++;
|
clks_exec_requests++;
|
||||||
|
|
||||||
@@ -64,37 +147,78 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
|
|||||||
*out_status = (u64)-1;
|
*out_status = (u64)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (out_pid != CLKS_NULL) {
|
||||||
|
*out_pid = (u64)-1;
|
||||||
|
}
|
||||||
|
|
||||||
if (path == CLKS_NULL || path[0] != '/') {
|
if (path == CLKS_NULL || path[0] != '/') {
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", "INVALID EXEC PATH");
|
clks_log(CLKS_LOG_WARN, "EXEC", "INVALID EXEC PATH");
|
||||||
return CLKS_FALSE;
|
return CLKS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slot = clks_exec_proc_alloc_slot();
|
||||||
|
|
||||||
|
if (slot < 0) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS TABLE FULL");
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_exec_pid_stack_depth >= CLKS_EXEC_MAX_DEPTH) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS STACK DEPTH EXCEEDED");
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = clks_exec_next_pid;
|
||||||
|
clks_exec_next_pid++;
|
||||||
|
|
||||||
|
if (clks_exec_next_pid == 0ULL) {
|
||||||
|
clks_exec_next_pid = 1ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc = &clks_exec_proc_table[(u32)slot];
|
||||||
|
clks_memset(proc, 0, sizeof(*proc));
|
||||||
|
|
||||||
|
proc->used = CLKS_TRUE;
|
||||||
|
proc->state = CLKS_EXEC_PROC_RUNNING;
|
||||||
|
proc->pid = pid;
|
||||||
|
proc->ppid = clks_exec_current_pid();
|
||||||
|
proc->started_tick = clks_interrupts_timer_ticks();
|
||||||
|
proc->exit_status = (u64)-1;
|
||||||
|
clks_exec_copy_path(proc->path, sizeof(proc->path), path);
|
||||||
|
|
||||||
|
depth_index = (i32)clks_exec_pid_stack_depth;
|
||||||
|
clks_exec_pid_stack[(u32)depth_index] = pid;
|
||||||
|
clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_FALSE;
|
||||||
|
clks_exec_exit_status_stack[(u32)depth_index] = 0ULL;
|
||||||
|
clks_exec_pid_stack_depth++;
|
||||||
|
|
||||||
image = clks_fs_read_all(path, &image_size);
|
image = clks_fs_read_all(path, &image_size);
|
||||||
|
|
||||||
if (image == CLKS_NULL || image_size == 0ULL) {
|
if (image == CLKS_NULL || image_size == 0ULL) {
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC FILE MISSING");
|
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC FILE MISSING");
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
||||||
return CLKS_FALSE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) {
|
if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) {
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF INVALID");
|
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF INVALID");
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
||||||
return CLKS_FALSE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clks_elf64_load(image, image_size, &loaded) == CLKS_FALSE) {
|
if (clks_elf64_load(image, image_size, &loaded) == CLKS_FALSE) {
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF LOAD FAILED");
|
clks_log(CLKS_LOG_WARN, "EXEC", "EXEC ELF LOAD FAILED");
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
||||||
return CLKS_FALSE;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loaded_active = CLKS_TRUE;
|
||||||
|
|
||||||
entry_ptr = clks_elf64_entry_pointer(&loaded, info.entry);
|
entry_ptr = clks_elf64_entry_pointer(&loaded, info.entry);
|
||||||
if (entry_ptr == CLKS_NULL) {
|
if (entry_ptr == CLKS_NULL) {
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", "ENTRY POINTER RESOLVE FAILED");
|
clks_log(CLKS_LOG_WARN, "EXEC", "ENTRY POINTER RESOLVE FAILED");
|
||||||
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
||||||
clks_elf64_unload(&loaded);
|
goto fail;
|
||||||
return CLKS_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clks_log(CLKS_LOG_INFO, "EXEC", "EXEC RUN START");
|
clks_log(CLKS_LOG_INFO, "EXEC", "EXEC RUN START");
|
||||||
@@ -110,25 +234,154 @@ clks_bool clks_exec_run_path(const char *path, u64 *out_status) {
|
|||||||
|
|
||||||
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", path);
|
clks_log(CLKS_LOG_WARN, "EXEC", path);
|
||||||
clks_elf64_unload(&loaded);
|
goto fail;
|
||||||
return CLKS_FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clks_exec_running_depth > 0U) {
|
if (clks_exec_running_depth > 0U) {
|
||||||
clks_exec_running_depth--;
|
clks_exec_running_depth--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clks_exec_exit_requested_stack[(u32)depth_index] == CLKS_TRUE) {
|
||||||
|
run_ret = clks_exec_exit_status_stack[(u32)depth_index];
|
||||||
|
}
|
||||||
|
|
||||||
clks_log(CLKS_LOG_INFO, "EXEC", "RUN RETURNED");
|
clks_log(CLKS_LOG_INFO, "EXEC", "RUN RETURNED");
|
||||||
clks_log(CLKS_LOG_INFO, "EXEC", path);
|
clks_log(CLKS_LOG_INFO, "EXEC", path);
|
||||||
clks_log_hex(CLKS_LOG_INFO, "EXEC", "RET", run_ret);
|
clks_log_hex(CLKS_LOG_INFO, "EXEC", "RET", run_ret);
|
||||||
|
|
||||||
clks_exec_success++;
|
clks_exec_success++;
|
||||||
|
|
||||||
|
proc->state = CLKS_EXEC_PROC_EXITED;
|
||||||
|
proc->exit_status = run_ret;
|
||||||
|
proc->exited_tick = clks_interrupts_timer_ticks();
|
||||||
|
|
||||||
|
clks_exec_pid_stack_depth--;
|
||||||
|
|
||||||
|
if (loaded_active == CLKS_TRUE) {
|
||||||
|
clks_elf64_unload(&loaded);
|
||||||
|
}
|
||||||
|
|
||||||
if (out_status != CLKS_NULL) {
|
if (out_status != CLKS_NULL) {
|
||||||
*out_status = run_ret;
|
*out_status = run_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
clks_elf64_unload(&loaded);
|
if (out_pid != CLKS_NULL) {
|
||||||
|
*out_pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
return CLKS_TRUE;
|
return CLKS_TRUE;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
proc->state = CLKS_EXEC_PROC_EXITED;
|
||||||
|
proc->exit_status = (u64)-1;
|
||||||
|
proc->exited_tick = clks_interrupts_timer_ticks();
|
||||||
|
|
||||||
|
clks_exec_pid_stack_depth--;
|
||||||
|
|
||||||
|
if (loaded_active == CLKS_TRUE) {
|
||||||
|
clks_elf64_unload(&loaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_status != CLKS_NULL) {
|
||||||
|
*out_status = (u64)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_exec_init(void) {
|
||||||
|
clks_exec_requests = 0ULL;
|
||||||
|
clks_exec_success = 0ULL;
|
||||||
|
clks_exec_running_depth = 0U;
|
||||||
|
clks_exec_next_pid = 1ULL;
|
||||||
|
clks_exec_pid_stack_depth = 0U;
|
||||||
|
clks_memset(clks_exec_pid_stack, 0, sizeof(clks_exec_pid_stack));
|
||||||
|
clks_memset(clks_exec_exit_requested_stack, 0, sizeof(clks_exec_exit_requested_stack));
|
||||||
|
clks_memset(clks_exec_exit_status_stack, 0, sizeof(clks_exec_exit_status_stack));
|
||||||
|
clks_memset(clks_exec_proc_table, 0, sizeof(clks_exec_proc_table));
|
||||||
|
clks_log(CLKS_LOG_INFO, "EXEC", "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);
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_bool clks_exec_spawn_path(const char *path, u64 *out_pid) {
|
||||||
|
u64 status = (u64)-1;
|
||||||
|
return clks_exec_run_path_internal(path, &status, out_pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 clks_exec_wait_pid(u64 pid, u64 *out_status) {
|
||||||
|
i32 slot;
|
||||||
|
const struct clks_exec_proc_record *proc;
|
||||||
|
|
||||||
|
slot = clks_exec_proc_find_slot_by_pid(pid);
|
||||||
|
|
||||||
|
if (slot < 0) {
|
||||||
|
return (u64)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc = &clks_exec_proc_table[(u32)slot];
|
||||||
|
|
||||||
|
if (proc->state == CLKS_EXEC_PROC_RUNNING) {
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_status != CLKS_NULL) {
|
||||||
|
*out_status = proc->exit_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_bool clks_exec_request_exit(u64 status) {
|
||||||
|
i32 depth_index = clks_exec_current_depth_index();
|
||||||
|
|
||||||
|
if (depth_index < 0) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE;
|
||||||
|
clks_exec_exit_status_stack[(u32)depth_index] = status;
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 clks_exec_current_pid(void) {
|
||||||
|
i32 depth_index = clks_exec_current_depth_index();
|
||||||
|
|
||||||
|
if (depth_index < 0) {
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clks_exec_pid_stack[(u32)depth_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 clks_exec_sleep_ticks(u64 ticks) {
|
||||||
|
u64 start = clks_interrupts_timer_ticks();
|
||||||
|
|
||||||
|
if (ticks == 0ULL) {
|
||||||
|
return 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((clks_interrupts_timer_ticks() - start) < ticks) {
|
||||||
|
#if defined(CLKS_ARCH_X86_64)
|
||||||
|
__asm__ volatile("sti; hlt; cli" : : : "memory");
|
||||||
|
#elif defined(CLKS_ARCH_AARCH64)
|
||||||
|
clks_cpu_pause();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return clks_interrupts_timer_ticks() - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 clks_exec_yield(void) {
|
||||||
|
#if defined(CLKS_ARCH_X86_64)
|
||||||
|
__asm__ volatile("sti; hlt; cli" : : : "memory");
|
||||||
|
#elif defined(CLKS_ARCH_AARCH64)
|
||||||
|
clks_cpu_pause();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return clks_interrupts_timer_ticks();
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 clks_exec_request_count(void) {
|
u64 clks_exec_request_count(void) {
|
||||||
@@ -142,4 +395,3 @@ u64 clks_exec_success_count(void) {
|
|||||||
clks_bool clks_exec_is_running(void) {
|
clks_bool clks_exec_is_running(void) {
|
||||||
return (clks_exec_running_depth > 0U) ? CLKS_TRUE : CLKS_FALSE;
|
return (clks_exec_running_depth > 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,6 +200,48 @@ static u64 clks_syscall_exec_path(u64 arg0) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 clks_syscall_getpid(void) {
|
||||||
|
return clks_exec_current_pid();
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 clks_syscall_spawn_path(u64 arg0) {
|
||||||
|
char path[CLKS_SYSCALL_PATH_MAX];
|
||||||
|
u64 pid = (u64)-1;
|
||||||
|
|
||||||
|
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
|
||||||
|
return (u64)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_exec_spawn_path(path, &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);
|
||||||
|
|
||||||
|
if (wait_ret == 1ULL && arg1 != 0ULL) {
|
||||||
|
clks_memcpy((void *)arg1, &status, sizeof(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return wait_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 clks_syscall_exit(u64 arg0) {
|
||||||
|
return (clks_exec_request_exit(arg0) == CLKS_TRUE) ? 1ULL : 0ULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 clks_syscall_sleep_ticks(u64 arg0) {
|
||||||
|
return clks_exec_sleep_ticks(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 clks_syscall_yield(void) {
|
||||||
|
return clks_exec_yield();
|
||||||
|
}
|
||||||
|
|
||||||
static u64 clks_syscall_fs_stat_type(u64 arg0) {
|
static u64 clks_syscall_fs_stat_type(u64 arg0) {
|
||||||
char path[CLKS_SYSCALL_PATH_MAX];
|
char path[CLKS_SYSCALL_PATH_MAX];
|
||||||
struct clks_fs_node_info info;
|
struct clks_fs_node_info info;
|
||||||
@@ -436,6 +478,18 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
|
|||||||
return clks_keyboard_drop_count();
|
return clks_keyboard_drop_count();
|
||||||
case CLKS_SYSCALL_KBD_HOTKEY_SWITCHES:
|
case CLKS_SYSCALL_KBD_HOTKEY_SWITCHES:
|
||||||
return clks_keyboard_hotkey_switch_count();
|
return clks_keyboard_hotkey_switch_count();
|
||||||
|
case CLKS_SYSCALL_GETPID:
|
||||||
|
return clks_syscall_getpid();
|
||||||
|
case CLKS_SYSCALL_SPAWN_PATH:
|
||||||
|
return clks_syscall_spawn_path(frame->rbx);
|
||||||
|
case CLKS_SYSCALL_WAITPID:
|
||||||
|
return clks_syscall_waitpid(frame->rbx, frame->rcx);
|
||||||
|
case CLKS_SYSCALL_EXIT:
|
||||||
|
return clks_syscall_exit(frame->rbx);
|
||||||
|
case CLKS_SYSCALL_SLEEP_TICKS:
|
||||||
|
return clks_syscall_sleep_ticks(frame->rbx);
|
||||||
|
case CLKS_SYSCALL_YIELD:
|
||||||
|
return clks_syscall_yield();
|
||||||
default:
|
default:
|
||||||
return (u64)-1;
|
return (u64)-1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,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~39)
|
## 4. Syscall 列表(0~45)
|
||||||
|
|
||||||
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
|
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
|
||||||
|
|
||||||
@@ -294,6 +294,50 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
|||||||
- 参数:无
|
- 参数:无
|
||||||
- 返回:ALT+F1..F4 热键切换计数
|
- 返回:ALT+F1..F4 热键切换计数
|
||||||
|
|
||||||
|
### 40 `CLEONOS_SYSCALL_GETPID`
|
||||||
|
|
||||||
|
- 参数:无
|
||||||
|
- 返回:当前进程 PID(无活动进程时为 `0`)
|
||||||
|
|
||||||
|
### 41 `CLEONOS_SYSCALL_SPAWN_PATH`
|
||||||
|
|
||||||
|
- 参数:
|
||||||
|
- `arg0`: `const char *path`
|
||||||
|
- 返回:
|
||||||
|
- 成功:子进程 PID
|
||||||
|
- 失败:`-1`
|
||||||
|
- 说明:当前 Stage27 为同步 spawn(内部会执行完成后再返回 PID)。
|
||||||
|
|
||||||
|
### 42 `CLEONOS_SYSCALL_WAITPID`
|
||||||
|
|
||||||
|
- 参数:
|
||||||
|
- `arg0`: `u64 pid`
|
||||||
|
- `arg1`: `u64 *out_status`(可为 `0`)
|
||||||
|
- 返回:
|
||||||
|
- `-1`:PID 不存在
|
||||||
|
- `0`:目标进程仍在运行
|
||||||
|
- `1`:目标进程已退出
|
||||||
|
- 说明:当返回 `1` 且 `arg1!=0` 时,会写入退出码。
|
||||||
|
|
||||||
|
### 43 `CLEONOS_SYSCALL_EXIT`
|
||||||
|
|
||||||
|
- 参数:
|
||||||
|
- `arg0`: `u64 status`
|
||||||
|
- 返回:
|
||||||
|
- `1`:已记录退出请求
|
||||||
|
- `0`:当前上下文不支持退出请求
|
||||||
|
|
||||||
|
### 44 `CLEONOS_SYSCALL_SLEEP_TICKS`
|
||||||
|
|
||||||
|
- 参数:
|
||||||
|
- `arg0`: `u64 ticks`
|
||||||
|
- 返回:实际休眠 tick 数
|
||||||
|
|
||||||
|
### 45 `CLEONOS_SYSCALL_YIELD`
|
||||||
|
|
||||||
|
- 参数:无
|
||||||
|
- 返回:当前 tick
|
||||||
|
|
||||||
## 5. 用户态封装函数
|
## 5. 用户态封装函数
|
||||||
|
|
||||||
用户态封装位于:
|
用户态封装位于:
|
||||||
@@ -308,9 +352,11 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
|
|||||||
- `cleonos_sys_exec_path()`
|
- `cleonos_sys_exec_path()`
|
||||||
- `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_exit()` / `cleonos_sys_sleep_ticks()` / `cleonos_sys_yield()`
|
||||||
|
|
||||||
## 6. 开发注意事项
|
## 6. 开发注意事项
|
||||||
|
|
||||||
- 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。
|
- 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。
|
||||||
- `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`。
|
- `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`。
|
||||||
- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。
|
- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。`n
|
||||||
@@ -37,14 +37,15 @@ 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..39
|
- CLeonOS `int 0x80` syscall 0..45
|
||||||
- TTY 输出与键盘输入队列
|
- TTY 输出与键盘输入队列
|
||||||
- rootfs 文件/目录访问(`FS_*`)
|
- rootfs 文件/目录访问(`FS_*`)
|
||||||
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
||||||
- `EXEC_PATH` 递归执行 ELF(带深度限制)
|
- `EXEC_PATH` 递归执行 ELF(带深度限制)
|
||||||
|
- 进程生命周期 syscall(`GETPID/SPAWN_PATH/WAITPID/EXIT/SLEEP_TICKS/YIELD`)
|
||||||
|
|
||||||
## 参数
|
## 参数
|
||||||
|
|
||||||
- `--no-kbd`:关闭输入线程
|
- `--no-kbd`:关闭输入线程
|
||||||
- `--max-exec-depth N`:设置 exec 嵌套深度上限
|
- `--max-exec-depth N`:设置 exec 嵌套深度上限
|
||||||
- `--verbose`:打印更多日志
|
- `--verbose`:打印更多日志`n
|
||||||
@@ -48,6 +48,12 @@ SYS_KBD_PUSHED = 36
|
|||||||
SYS_KBD_POPPED = 37
|
SYS_KBD_POPPED = 37
|
||||||
SYS_KBD_DROPPED = 38
|
SYS_KBD_DROPPED = 38
|
||||||
SYS_KBD_HOTKEY_SWITCHES = 39
|
SYS_KBD_HOTKEY_SWITCHES = 39
|
||||||
|
SYS_GETPID = 40
|
||||||
|
SYS_SPAWN_PATH = 41
|
||||||
|
SYS_WAITPID = 42
|
||||||
|
SYS_EXIT = 43
|
||||||
|
SYS_SLEEP_TICKS = 44
|
||||||
|
SYS_YIELD = 45
|
||||||
|
|
||||||
|
|
||||||
def u64(value: int) -> int:
|
def u64(value: int) -> int:
|
||||||
@@ -63,4 +69,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)`n
|
||||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
import os
|
import os
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
@@ -18,6 +19,12 @@ from .constants import (
|
|||||||
SYS_EXEC_PATH,
|
SYS_EXEC_PATH,
|
||||||
SYS_EXEC_REQUESTS,
|
SYS_EXEC_REQUESTS,
|
||||||
SYS_EXEC_SUCCESS,
|
SYS_EXEC_SUCCESS,
|
||||||
|
SYS_EXIT,
|
||||||
|
SYS_GETPID,
|
||||||
|
SYS_SLEEP_TICKS,
|
||||||
|
SYS_SPAWN_PATH,
|
||||||
|
SYS_WAITPID,
|
||||||
|
SYS_YIELD,
|
||||||
SYS_FS_APPEND,
|
SYS_FS_APPEND,
|
||||||
SYS_FS_CHILD_COUNT,
|
SYS_FS_CHILD_COUNT,
|
||||||
SYS_FS_GET_CHILD_NAME,
|
SYS_FS_GET_CHILD_NAME,
|
||||||
@@ -107,6 +114,8 @@ class CLeonOSWineNative:
|
|||||||
no_kbd: bool = False,
|
no_kbd: bool = False,
|
||||||
verbose: bool = False,
|
verbose: bool = False,
|
||||||
top_level: bool = True,
|
top_level: bool = True,
|
||||||
|
pid: int = 0,
|
||||||
|
ppid: int = 0,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.elf_path = elf_path
|
self.elf_path = elf_path
|
||||||
self.rootfs = rootfs
|
self.rootfs = rootfs
|
||||||
@@ -117,6 +126,10 @@ class CLeonOSWineNative:
|
|||||||
self.no_kbd = no_kbd
|
self.no_kbd = no_kbd
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.top_level = top_level
|
self.top_level = top_level
|
||||||
|
self.pid = int(pid)
|
||||||
|
self.ppid = int(ppid)
|
||||||
|
self._exit_requested = False
|
||||||
|
self._exit_status = 0
|
||||||
|
|
||||||
self.image = self._parse_elf(self.elf_path)
|
self.image = self._parse_elf(self.elf_path)
|
||||||
self.exit_code: Optional[int] = None
|
self.exit_code: Optional[int] = None
|
||||||
@@ -128,6 +141,12 @@ class CLeonOSWineNative:
|
|||||||
self._mapped_ranges: List[Tuple[int, int]] = []
|
self._mapped_ranges: List[Tuple[int, int]] = []
|
||||||
|
|
||||||
def run(self) -> Optional[int]:
|
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)
|
||||||
|
|
||||||
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||||
self._install_hooks(uc)
|
self._install_hooks(uc)
|
||||||
self._load_segments(uc)
|
self._load_segments(uc)
|
||||||
@@ -137,24 +156,37 @@ 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
|
||||||
|
|
||||||
try:
|
try:
|
||||||
uc.emu_start(self.image.entry, 0)
|
uc.emu_start(self.image.entry, 0)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
run_failed = 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)
|
||||||
return None
|
|
||||||
except UcError as exc:
|
except UcError as exc:
|
||||||
|
run_failed = True
|
||||||
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)
|
||||||
return None
|
|
||||||
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:
|
||||||
|
self.state.mark_exited(self.pid, u64_neg1())
|
||||||
|
self.state.set_current_pid(prev_pid)
|
||||||
|
return None
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
return u64(self.exit_code)
|
if self._exit_requested:
|
||||||
|
self.exit_code = self._exit_status
|
||||||
|
|
||||||
|
self.exit_code = u64(self.exit_code)
|
||||||
|
self.state.mark_exited(self.pid, self.exit_code)
|
||||||
|
self.state.set_current_pid(prev_pid)
|
||||||
|
return self.exit_code
|
||||||
|
|
||||||
def _install_hooks(self, uc: Uc) -> None:
|
def _install_hooks(self, uc: Uc) -> None:
|
||||||
uc.hook_add(UC_HOOK_INTR, self._hook_intr)
|
uc.hook_add(UC_HOOK_INTR, self._hook_intr)
|
||||||
@@ -212,6 +244,18 @@ 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_SPAWN_PATH:
|
||||||
|
return self._spawn_path(uc, arg0)
|
||||||
|
if sid == SYS_WAITPID:
|
||||||
|
return self._wait_pid(uc, arg0, arg1)
|
||||||
|
if sid == SYS_GETPID:
|
||||||
|
return self.state.get_current_pid()
|
||||||
|
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_EXEC_REQUESTS:
|
if sid == SYS_EXEC_REQUESTS:
|
||||||
return self.state.exec_requests
|
return self.state.exec_requests
|
||||||
if sid == SYS_EXEC_SUCCESS:
|
if sid == SYS_EXEC_SUCCESS:
|
||||||
@@ -618,6 +662,12 @@ 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)
|
||||||
|
|
||||||
|
def _spawn_path(self, uc: Uc, path_ptr: int) -> int:
|
||||||
|
return self._spawn_path_common(uc, path_ptr, 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)
|
path = self._read_guest_cstring(uc, path_ptr)
|
||||||
guest_path = self._normalize_guest_path(path)
|
guest_path = self._normalize_guest_path(path)
|
||||||
host_path = self._guest_to_host(guest_path, must_exist=True)
|
host_path = self._guest_to_host(guest_path, must_exist=True)
|
||||||
@@ -635,6 +685,9 @@ class CLeonOSWineNative:
|
|||||||
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
|
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
|
||||||
return u64_neg1()
|
return u64_neg1()
|
||||||
|
|
||||||
|
parent_pid = self.state.get_current_pid()
|
||||||
|
child_pid = self.state.alloc_pid(parent_pid)
|
||||||
|
|
||||||
child = CLeonOSWineNative(
|
child = CLeonOSWineNative(
|
||||||
elf_path=host_path,
|
elf_path=host_path,
|
||||||
rootfs=self.rootfs,
|
rootfs=self.rootfs,
|
||||||
@@ -645,18 +698,57 @@ class CLeonOSWineNative:
|
|||||||
no_kbd=True,
|
no_kbd=True,
|
||||||
verbose=self.verbose,
|
verbose=self.verbose,
|
||||||
top_level=False,
|
top_level=False,
|
||||||
|
pid=child_pid,
|
||||||
|
ppid=parent_pid,
|
||||||
)
|
)
|
||||||
child_ret = child.run()
|
child_ret = child.run()
|
||||||
|
|
||||||
if child_ret is None:
|
if child_ret is None:
|
||||||
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
|
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
|
||||||
return u64_neg1()
|
return u64_neg1()
|
||||||
|
|
||||||
self.state.exec_success = u64(self.state.exec_success + 1)
|
self.state.exec_success = u64(self.state.exec_success + 1)
|
||||||
self.state.user_launch_ok = u64(self.state.user_launch_ok + 1)
|
self.state.user_launch_ok = u64(self.state.user_launch_ok + 1)
|
||||||
|
|
||||||
if guest_path.lower().startswith("/system/"):
|
if guest_path.lower().startswith("/system/"):
|
||||||
self.state.kelf_runs = u64(self.state.kelf_runs + 1)
|
self.state.kelf_runs = u64(self.state.kelf_runs + 1)
|
||||||
|
|
||||||
|
if return_pid:
|
||||||
|
return child_pid
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int:
|
||||||
|
wait_ret, status = self.state.wait_pid(int(pid))
|
||||||
|
|
||||||
|
if wait_ret == 1 and out_ptr != 0:
|
||||||
|
self._write_guest_bytes(uc, out_ptr, struct.pack("<Q", u64(status)))
|
||||||
|
|
||||||
|
return int(wait_ret)
|
||||||
|
|
||||||
|
def _request_exit(self, uc: Uc, status: int) -> int:
|
||||||
|
self._exit_requested = True
|
||||||
|
self._exit_status = u64(status)
|
||||||
|
uc.emu_stop()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def _sleep_ticks(self, ticks: int) -> int:
|
||||||
|
ticks = int(u64(ticks))
|
||||||
|
|
||||||
|
if ticks == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
start = self.state.timer_ticks()
|
||||||
|
|
||||||
|
while (self.state.timer_ticks() - start) < ticks:
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
|
return self.state.timer_ticks() - start
|
||||||
|
|
||||||
|
def _yield_once(self) -> int:
|
||||||
|
time.sleep(0)
|
||||||
|
return self.state.timer_ticks()
|
||||||
|
|
||||||
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 == "/":
|
||||||
@@ -782,4 +874,4 @@ def resolve_elf_target(elf_arg: str, rootfs: Path) -> Tuple[Path, str]:
|
|||||||
host_path = _guest_to_host_for_resolve(rootfs, guest_path)
|
host_path = _guest_to_host_for_resolve(rootfs, guest_path)
|
||||||
if host_path is None:
|
if host_path is None:
|
||||||
raise FileNotFoundError(f"ELF not found as host path or guest path: {elf_arg}")
|
raise FileNotFoundError(f"ELF not found as host path or guest path: {elf_arg}")
|
||||||
return host_path.resolve(), guest_path
|
return host_path.resolve(), guest_path`n
|
||||||
@@ -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, Optional
|
from typing import Deque, Dict, Optional, Tuple
|
||||||
|
|
||||||
from .constants import u64
|
from .constants import u64
|
||||||
|
|
||||||
@@ -39,6 +39,12 @@ class SharedKernelState:
|
|||||||
log_journal: Deque[str] = field(default_factory=lambda: collections.deque(maxlen=256))
|
log_journal: Deque[str] = field(default_factory=lambda: collections.deque(maxlen=256))
|
||||||
fs_write_max: int = 65536
|
fs_write_max: int = 65536
|
||||||
|
|
||||||
|
proc_lock: threading.Lock = field(default_factory=threading.Lock)
|
||||||
|
proc_next_pid: int = 1
|
||||||
|
proc_current_pid: int = 0
|
||||||
|
proc_parents: Dict[int, int] = field(default_factory=dict)
|
||||||
|
proc_status: Dict[int, Optional[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
|
||||||
|
|
||||||
@@ -80,3 +86,46 @@ class SharedKernelState:
|
|||||||
if index_from_oldest < 0 or index_from_oldest >= len(self.log_journal):
|
if index_from_oldest < 0 or index_from_oldest >= len(self.log_journal):
|
||||||
return None
|
return None
|
||||||
return list(self.log_journal)[index_from_oldest]
|
return list(self.log_journal)[index_from_oldest]
|
||||||
|
|
||||||
|
def alloc_pid(self, ppid: int) -> int:
|
||||||
|
with self.proc_lock:
|
||||||
|
pid = int(self.proc_next_pid)
|
||||||
|
|
||||||
|
if pid == 0:
|
||||||
|
pid = 1
|
||||||
|
|
||||||
|
self.proc_next_pid = int(u64(pid + 1))
|
||||||
|
|
||||||
|
if self.proc_next_pid == 0:
|
||||||
|
self.proc_next_pid = 1
|
||||||
|
|
||||||
|
self.proc_parents[pid] = int(ppid)
|
||||||
|
self.proc_status[pid] = None
|
||||||
|
return pid
|
||||||
|
|
||||||
|
def set_current_pid(self, pid: int) -> None:
|
||||||
|
with self.proc_lock:
|
||||||
|
self.proc_current_pid = int(pid)
|
||||||
|
|
||||||
|
def get_current_pid(self) -> int:
|
||||||
|
with self.proc_lock:
|
||||||
|
return int(self.proc_current_pid)
|
||||||
|
|
||||||
|
def mark_exited(self, pid: int, status: int) -> None:
|
||||||
|
if pid <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
with self.proc_lock:
|
||||||
|
self.proc_status[int(pid)] = int(u64(status))
|
||||||
|
|
||||||
|
def wait_pid(self, pid: int) -> Tuple[int, int]:
|
||||||
|
with self.proc_lock:
|
||||||
|
if pid not in self.proc_status:
|
||||||
|
return int(u64(-1)), 0
|
||||||
|
|
||||||
|
status = self.proc_status[pid]
|
||||||
|
|
||||||
|
if status is None:
|
||||||
|
return 0, 0
|
||||||
|
|
||||||
|
return 1, int(status)`n
|
||||||
Reference in New Issue
Block a user