Files
cleonos/clks/kernel/syscall.c

565 lines
16 KiB
C
Raw Normal View History

2026-04-10 21:01:31 +08:00
#include <clks/exec.h>
#include <clks/fs.h>
2026-04-12 22:04:25 +08:00
#include <clks/heap.h>
2026-04-10 16:55:48 +08:00
#include <clks/interrupts.h>
2026-04-10 20:40:28 +08:00
#include <clks/kelf.h>
2026-04-11 14:18:59 +08:00
#include <clks/keyboard.h>
2026-04-10 16:55:48 +08:00
#include <clks/log.h>
2026-04-13 22:41:19 +08:00
#include <clks/serial.h>
2026-04-10 16:55:48 +08:00
#include <clks/scheduler.h>
2026-04-10 20:32:03 +08:00
#include <clks/service.h>
2026-04-10 21:01:31 +08:00
#include <clks/string.h>
2026-04-10 16:55:48 +08:00
#include <clks/syscall.h>
2026-04-10 22:23:44 +08:00
#include <clks/tty.h>
2026-04-10 16:55:48 +08:00
#include <clks/types.h>
2026-04-10 21:10:16 +08:00
#include <clks/userland.h>
2026-04-10 16:55:48 +08:00
2026-04-12 22:04:25 +08:00
#define CLKS_SYSCALL_LOG_MAX_LEN 191U
#define CLKS_SYSCALL_PATH_MAX 192U
#define CLKS_SYSCALL_NAME_MAX 96U
#define CLKS_SYSCALL_TTY_MAX_LEN 512U
#define CLKS_SYSCALL_FS_IO_MAX_LEN 65536U
#define CLKS_SYSCALL_JOURNAL_MAX_LEN 256U
2026-04-13 22:37:39 +08:00
#define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL
2026-04-10 21:01:31 +08:00
2026-04-10 16:55:48 +08:00
struct clks_syscall_frame {
u64 rax;
u64 rbx;
u64 rcx;
u64 rdx;
u64 rsi;
u64 rdi;
u64 rbp;
u64 r8;
u64 r9;
u64 r10;
u64 r11;
u64 r12;
u64 r13;
u64 r14;
u64 r15;
u64 vector;
u64 error_code;
u64 rip;
u64 cs;
u64 rflags;
u64 rsp;
u64 ss;
};
static clks_bool clks_syscall_ready = CLKS_FALSE;
2026-04-13 22:37:39 +08:00
static clks_bool clks_syscall_user_trace_active = CLKS_FALSE;
static u64 clks_syscall_user_trace_budget = 0ULL;
2026-04-10 16:55:48 +08:00
2026-04-10 21:01:31 +08:00
static clks_bool clks_syscall_copy_user_string(u64 src_addr, char *dst, usize dst_size) {
const char *src = (const char *)src_addr;
usize i = 0U;
if (src == CLKS_NULL || dst == CLKS_NULL || dst_size == 0U) {
return CLKS_FALSE;
}
while (i + 1U < dst_size) {
char ch = src[i];
dst[i] = ch;
if (ch == '\0') {
return CLKS_TRUE;
}
i++;
}
dst[dst_size - 1U] = '\0';
return CLKS_TRUE;
}
2026-04-10 16:55:48 +08:00
static u64 clks_syscall_log_write(u64 arg0, u64 arg1) {
const char *src = (const char *)arg0;
u64 len = arg1;
2026-04-10 21:01:31 +08:00
char buf[CLKS_SYSCALL_LOG_MAX_LEN + 1U];
2026-04-10 16:55:48 +08:00
u64 i;
if (src == CLKS_NULL || len == 0ULL) {
return 0ULL;
}
2026-04-10 21:01:31 +08:00
if (len > CLKS_SYSCALL_LOG_MAX_LEN) {
len = CLKS_SYSCALL_LOG_MAX_LEN;
2026-04-10 16:55:48 +08:00
}
2026-04-10 21:01:31 +08:00
for (i = 0ULL; i < len; i++) {
2026-04-10 16:55:48 +08:00
buf[i] = src[i];
}
buf[len] = '\0';
clks_log(CLKS_LOG_INFO, "SYSCALL", buf);
return len;
}
2026-04-11 14:18:59 +08:00
static u64 clks_syscall_tty_write(u64 arg0, u64 arg1) {
const char *src = (const char *)arg0;
u64 len = arg1;
2026-04-12 22:04:25 +08:00
char buf[CLKS_SYSCALL_TTY_MAX_LEN + 1U];
2026-04-11 14:18:59 +08:00
u64 i;
if (src == CLKS_NULL || len == 0ULL) {
return 0ULL;
}
2026-04-12 22:04:25 +08:00
if (len > CLKS_SYSCALL_TTY_MAX_LEN) {
len = CLKS_SYSCALL_TTY_MAX_LEN;
2026-04-11 14:18:59 +08:00
}
for (i = 0ULL; i < len; i++) {
buf[i] = src[i];
}
buf[len] = '\0';
clks_tty_write(buf);
return len;
}
static u64 clks_syscall_tty_write_char(u64 arg0) {
clks_tty_write_char((char)(arg0 & 0xFFULL));
return 1ULL;
}
static u64 clks_syscall_kbd_get_char(void) {
char ch;
2026-04-14 18:28:29 +08:00
u32 tty_index = clks_exec_current_tty();
2026-04-11 14:18:59 +08:00
2026-04-14 18:28:29 +08:00
if (clks_keyboard_pop_char_for_tty(tty_index, &ch) == CLKS_FALSE) {
2026-04-11 14:18:59 +08:00
return (u64)-1;
}
return (u64)(u8)ch;
}
2026-04-10 21:01:31 +08:00
static u64 clks_syscall_fs_child_count(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX];
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return (u64)-1;
}
return clks_fs_count_children(path);
}
static u64 clks_syscall_fs_get_child_name(u64 arg0, u64 arg1, u64 arg2) {
char path[CLKS_SYSCALL_PATH_MAX];
if (arg2 == 0ULL) {
return 0ULL;
}
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return 0ULL;
}
if (clks_fs_get_child_name(path, arg1, (char *)arg2, (usize)CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) {
return 0ULL;
}
return 1ULL;
}
static u64 clks_syscall_fs_read(u64 arg0, u64 arg1, u64 arg2) {
char path[CLKS_SYSCALL_PATH_MAX];
const void *data;
u64 file_size = 0ULL;
u64 copy_len;
if (arg1 == 0ULL || arg2 == 0ULL) {
return 0ULL;
}
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return 0ULL;
}
data = clks_fs_read_all(path, &file_size);
if (data == CLKS_NULL || file_size == 0ULL) {
return 0ULL;
}
copy_len = (file_size < arg2) ? file_size : arg2;
clks_memcpy((void *)arg1, data, (usize)copy_len);
return copy_len;
}
static u64 clks_syscall_exec_path(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX];
u64 status = (u64)-1;
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return (u64)-1;
}
if (clks_exec_run_path(path, &status) == CLKS_FALSE) {
return (u64)-1;
}
return status;
}
2026-04-13 19:08:35 +08:00
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();
}
2026-04-12 22:04:25 +08:00
static u64 clks_syscall_fs_stat_type(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX];
struct clks_fs_node_info info;
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return (u64)-1;
}
if (clks_fs_stat(path, &info) == CLKS_FALSE) {
return (u64)-1;
}
return (u64)info.type;
}
static u64 clks_syscall_fs_stat_size(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX];
struct clks_fs_node_info info;
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return (u64)-1;
}
if (clks_fs_stat(path, &info) == CLKS_FALSE) {
return (u64)-1;
}
return info.size;
}
static u64 clks_syscall_fs_mkdir(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX];
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return 0ULL;
}
return (clks_fs_mkdir(path) == CLKS_TRUE) ? 1ULL : 0ULL;
}
static u64 clks_syscall_fs_write_common(u64 arg0, u64 arg1, u64 arg2, clks_bool append_mode) {
char path[CLKS_SYSCALL_PATH_MAX];
void *heap_copy = CLKS_NULL;
const void *payload = CLKS_NULL;
clks_bool ok;
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return 0ULL;
}
if (arg2 > CLKS_SYSCALL_FS_IO_MAX_LEN) {
return 0ULL;
}
if (arg2 > 0ULL) {
if (arg1 == 0ULL) {
return 0ULL;
}
heap_copy = clks_kmalloc((usize)arg2);
if (heap_copy == CLKS_NULL) {
return 0ULL;
}
clks_memcpy(heap_copy, (const void *)arg1, (usize)arg2);
payload = (const void *)heap_copy;
}
if (append_mode == CLKS_TRUE) {
ok = clks_fs_append(path, payload, arg2);
} else {
ok = clks_fs_write_all(path, payload, arg2);
}
if (heap_copy != CLKS_NULL) {
clks_kfree(heap_copy);
}
return (ok == CLKS_TRUE) ? 1ULL : 0ULL;
}
static u64 clks_syscall_fs_write(u64 arg0, u64 arg1, u64 arg2) {
return clks_syscall_fs_write_common(arg0, arg1, arg2, CLKS_FALSE);
}
static u64 clks_syscall_fs_append(u64 arg0, u64 arg1, u64 arg2) {
return clks_syscall_fs_write_common(arg0, arg1, arg2, CLKS_TRUE);
}
static u64 clks_syscall_fs_remove(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX];
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return 0ULL;
}
return (clks_fs_remove(path) == CLKS_TRUE) ? 1ULL : 0ULL;
}
static u64 clks_syscall_log_journal_count(void) {
return clks_log_journal_count();
}
static u64 clks_syscall_log_journal_read(u64 arg0, u64 arg1, u64 arg2) {
char line[CLKS_SYSCALL_JOURNAL_MAX_LEN];
usize line_len;
usize copy_len;
if (arg1 == 0ULL || arg2 == 0ULL) {
return 0ULL;
}
if (clks_log_journal_read(arg0, line, sizeof(line)) == CLKS_FALSE) {
return 0ULL;
}
line_len = clks_strlen(line) + 1U;
copy_len = line_len;
if (copy_len > (usize)arg2) {
copy_len = (usize)arg2;
}
if (copy_len > sizeof(line)) {
copy_len = sizeof(line);
}
clks_memcpy((void *)arg1, line, copy_len);
((char *)arg1)[copy_len - 1U] = '\0';
return 1ULL;
}
2026-04-13 22:41:19 +08:00
static void clks_syscall_serial_write_hex64(u64 value) {
i32 nibble;
for (nibble = 15; nibble >= 0; nibble--) {
u64 current = (value >> (u64)(nibble * 4)) & 0x0FULL;
char ch = (current < 10ULL) ? (char)('0' + current) : (char)('A' + (current - 10ULL));
clks_serial_write_char(ch);
}
}
2026-04-13 22:37:39 +08:00
static void clks_syscall_trace_user_program(u64 id) {
clks_bool user_program_running =
(clks_exec_is_running() == CLKS_TRUE && clks_exec_current_path_is_user() == CLKS_TRUE)
? CLKS_TRUE
: CLKS_FALSE;
if (user_program_running == CLKS_FALSE) {
if (clks_syscall_user_trace_active == CLKS_TRUE) {
2026-04-13 22:41:19 +08:00
clks_serial_write("[DEBUG][SYSCALL] USER_TRACE_END\n");
2026-04-13 22:37:39 +08:00
}
clks_syscall_user_trace_active = CLKS_FALSE;
clks_syscall_user_trace_budget = 0ULL;
return;
}
if (clks_syscall_user_trace_active == CLKS_FALSE) {
clks_syscall_user_trace_active = CLKS_TRUE;
clks_syscall_user_trace_budget = CLKS_SYSCALL_USER_TRACE_BUDGET;
2026-04-13 22:41:19 +08:00
clks_serial_write("[DEBUG][SYSCALL] USER_TRACE_BEGIN\n");
clks_serial_write("[DEBUG][SYSCALL] PID: 0X");
clks_syscall_serial_write_hex64(clks_exec_current_pid());
clks_serial_write("\n");
2026-04-13 22:37:39 +08:00
}
if (clks_syscall_user_trace_budget > 0ULL) {
2026-04-13 22:41:19 +08:00
clks_serial_write("[DEBUG][SYSCALL] USER_ID: 0X");
clks_syscall_serial_write_hex64(id);
clks_serial_write("\n");
2026-04-13 22:37:39 +08:00
clks_syscall_user_trace_budget--;
if (clks_syscall_user_trace_budget == 0ULL) {
2026-04-13 22:41:19 +08:00
clks_serial_write("[DEBUG][SYSCALL] USER_TRACE_BUDGET_EXHAUSTED\n");
2026-04-13 22:37:39 +08:00
}
}
}
2026-04-10 16:55:48 +08:00
void clks_syscall_init(void) {
clks_syscall_ready = CLKS_TRUE;
2026-04-13 22:37:39 +08:00
clks_syscall_user_trace_active = CLKS_FALSE;
clks_syscall_user_trace_budget = 0ULL;
2026-04-10 16:55:48 +08:00
clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE");
}
u64 clks_syscall_dispatch(void *frame_ptr) {
struct clks_syscall_frame *frame = (struct clks_syscall_frame *)frame_ptr;
u64 id;
if (clks_syscall_ready == CLKS_FALSE || frame == CLKS_NULL) {
return (u64)-1;
}
id = frame->rax;
2026-04-13 22:37:39 +08:00
clks_syscall_trace_user_program(id);
2026-04-10 16:55:48 +08:00
switch (id) {
case CLKS_SYSCALL_LOG_WRITE:
return clks_syscall_log_write(frame->rbx, frame->rcx);
case CLKS_SYSCALL_TIMER_TICKS:
return clks_interrupts_timer_ticks();
case CLKS_SYSCALL_TASK_COUNT: {
struct clks_scheduler_stats stats = clks_scheduler_get_stats();
return stats.task_count;
}
case CLKS_SYSCALL_CURRENT_TASK_ID: {
struct clks_scheduler_stats stats = clks_scheduler_get_stats();
return stats.current_task_id;
}
2026-04-10 20:32:03 +08:00
case CLKS_SYSCALL_SERVICE_COUNT:
return clks_service_count();
case CLKS_SYSCALL_SERVICE_READY_COUNT:
return clks_service_ready_count();
case CLKS_SYSCALL_CONTEXT_SWITCHES: {
struct clks_scheduler_stats stats = clks_scheduler_get_stats();
return stats.context_switch_count;
}
2026-04-10 20:40:28 +08:00
case CLKS_SYSCALL_KELF_COUNT:
return clks_kelf_count();
case CLKS_SYSCALL_KELF_RUNS:
return clks_kelf_total_runs();
2026-04-10 21:01:31 +08:00
case CLKS_SYSCALL_FS_NODE_COUNT:
return clks_fs_node_count();
case CLKS_SYSCALL_FS_CHILD_COUNT:
return clks_syscall_fs_child_count(frame->rbx);
case CLKS_SYSCALL_FS_GET_CHILD_NAME:
return clks_syscall_fs_get_child_name(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_FS_READ:
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_REQUESTS:
return clks_exec_request_count();
case CLKS_SYSCALL_EXEC_SUCCESS:
return clks_exec_success_count();
2026-04-10 21:10:16 +08:00
case CLKS_SYSCALL_USER_SHELL_READY:
return (clks_userland_shell_ready() == CLKS_TRUE) ? 1ULL : 0ULL;
case CLKS_SYSCALL_USER_EXEC_REQUESTED:
return (clks_userland_shell_exec_requested() == CLKS_TRUE) ? 1ULL : 0ULL;
case CLKS_SYSCALL_USER_LAUNCH_TRIES:
return clks_userland_launch_attempts();
case CLKS_SYSCALL_USER_LAUNCH_OK:
return clks_userland_launch_success();
case CLKS_SYSCALL_USER_LAUNCH_FAIL:
return clks_userland_launch_failures();
2026-04-10 22:23:44 +08:00
case CLKS_SYSCALL_TTY_COUNT:
return (u64)clks_tty_count();
case CLKS_SYSCALL_TTY_ACTIVE:
return (u64)clks_tty_active();
case CLKS_SYSCALL_TTY_SWITCH:
clks_tty_switch((u32)frame->rbx);
return (u64)clks_tty_active();
2026-04-11 14:18:59 +08:00
case CLKS_SYSCALL_TTY_WRITE:
return clks_syscall_tty_write(frame->rbx, frame->rcx);
case CLKS_SYSCALL_TTY_WRITE_CHAR:
return clks_syscall_tty_write_char(frame->rbx);
case CLKS_SYSCALL_KBD_GET_CHAR:
return clks_syscall_kbd_get_char();
2026-04-12 22:04:25 +08:00
case CLKS_SYSCALL_FS_STAT_TYPE:
return clks_syscall_fs_stat_type(frame->rbx);
case CLKS_SYSCALL_FS_STAT_SIZE:
return clks_syscall_fs_stat_size(frame->rbx);
case CLKS_SYSCALL_FS_MKDIR:
return clks_syscall_fs_mkdir(frame->rbx);
case CLKS_SYSCALL_FS_WRITE:
return clks_syscall_fs_write(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_FS_APPEND:
return clks_syscall_fs_append(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_FS_REMOVE:
return clks_syscall_fs_remove(frame->rbx);
case CLKS_SYSCALL_LOG_JOURNAL_COUNT:
return clks_syscall_log_journal_count();
case CLKS_SYSCALL_LOG_JOURNAL_READ:
return clks_syscall_log_journal_read(frame->rbx, frame->rcx, frame->rdx);
case CLKS_SYSCALL_KBD_BUFFERED:
return clks_keyboard_buffered_count();
case CLKS_SYSCALL_KBD_PUSHED:
return clks_keyboard_push_count();
case CLKS_SYSCALL_KBD_POPPED:
return clks_keyboard_pop_count();
case CLKS_SYSCALL_KBD_DROPPED:
return clks_keyboard_drop_count();
case CLKS_SYSCALL_KBD_HOTKEY_SWITCHES:
return clks_keyboard_hotkey_switch_count();
2026-04-13 19:08:35 +08:00
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();
2026-04-10 16:55:48 +08:00
default:
return (u64)-1;
}
}
u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2) {
u64 ret;
__asm__ volatile(
"int $0x80"
: "=a"(ret)
: "a"(id), "b"(arg0), "c"(arg1), "d"(arg2)
: "memory"
);
return ret;
2026-04-13 22:37:39 +08:00
}