// Copyright (c) 2023-2026 Chris (boreddevnl) // This software is released under the GNU General Public License v3.0. See LICENSE file for details. // This header needs to maintain in any file it is present in, as per the GPL license terms. #include "syscall.h" #include "gdt.h" #include "memory_manager.h" #include "gui_ipc.h" #include "process.h" #include "wm.h" #include "fat32.h" #include "vfs.h" #include "paging.h" #include "work_queue.h" #include "smp.h" #include "platform.h" #include "io.h" #include "pci.h" #include "kutils.h" #include "network.h" #include "icmp.h" #include "cmd.h" #include "tty.h" #include "font_manager.h" #include "graphics.h" #include "input/keycodes.h" #include "input/keymap.h" #include "app_metadata.h" #include "disk.h" #include "mkfs_fat32.h" #define SYSTEM_CMD_DISK_GET_COUNT 100 #define SYSTEM_CMD_DISK_GET_INFO 101 #define SYSTEM_CMD_DISK_WRITE_GPT 102 #define SYSTEM_CMD_DISK_WRITE_MBR 103 #define SYSTEM_CMD_DISK_MKFS_FAT32 104 #define SYSTEM_CMD_DISK_MOUNT 105 #define SYSTEM_CMD_DISK_UMOUNT 106 #define SYSTEM_CMD_DISK_RESCAN 107 #define SYSTEM_CMD_DISK_REPLACE_KERNEL 108 #define SYSTEM_CMD_DISK_SYNC 109 #define SPAWN_FLAG_TERMINAL 0x1 #define SPAWN_FLAG_INHERIT_TTY 0x2 #define SPAWN_FLAG_TTY_ID 0x4 #define SYSTEM_CMD_SET_KEYBOARD_LAYOUT 49 #define SYSTEM_CMD_GET_KEYBOARD_LAYOUT 51 // Read MSR static inline uint64_t rdmsr(uint32_t msr) { uint32_t low, high; asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(msr)); return ((uint64_t)high << 32) | low; } // Write MSR static inline void wrmsr(uint32_t msr, uint64_t value) { uint32_t low = value & 0xFFFFFFFF; uint32_t high = value >> 32; asm volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high)); } extern void isr128_wrapper(void); extern void* kmalloc(size_t size); extern void kfree(void* ptr); typedef struct { void (*fn)(void *); void *arg; uint64_t pml4_phys; volatile int *completion_counter; } smp_user_task_t; static void smp_user_wrapper(void *arg) { smp_user_task_t *task = (smp_user_task_t *)arg; if (!task) return; uint64_t old_cr3; asm volatile("mov %%cr3, %0" : "=r"(old_cr3)); // Switch to user address space if necessary bool switch_cr3 = (task->pml4_phys != 0 && task->pml4_phys != old_cr3); if (switch_cr3) { asm volatile("mov %0, %%cr3" :: "r"(task->pml4_phys) : "memory"); } if (task->fn) { task->fn(task->arg); } if (switch_cr3) { asm volatile("mov %0, %%cr3" :: "r"(old_cr3) : "memory"); } if (task->completion_counter) { __sync_fetch_and_add(task->completion_counter, -1); } } void syscall_init(void) { uint64_t efer = rdmsr(MSR_EFER); efer |= 1; wrmsr(MSR_EFER, efer); uint64_t star = ((uint64_t)0x001B << 48) | ((uint64_t)0x0008 << 32); wrmsr(MSR_STAR, star); extern void syscall_entry(void); wrmsr(MSR_LSTAR, (uint64_t)syscall_entry); wrmsr(MSR_FMASK, 0x200); } static void user_window_close(Window *win) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_CLOSE }; process_push_gui_event(proc, &ev); } static void user_window_paint(Window *win) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_PAINT }; process_push_gui_event(proc, &ev); } static void user_window_click(Window *win, int x, int y) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_CLICK, .arg1 = x, .arg2 = y }; process_push_gui_event(proc, &ev); } static void user_window_right_click(Window *win, int x, int y) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_RIGHT_CLICK, .arg1 = x, .arg2 = y }; process_push_gui_event(proc, &ev); } static void user_window_mouse_down(Window *win, int x, int y) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_MOUSE_DOWN, .arg1 = x, .arg2 = y }; process_push_gui_event(proc, &ev); } static void user_window_mouse_up(Window *win, int x, int y) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_MOUSE_UP, .arg1 = x, .arg2 = y }; process_push_gui_event(proc, &ev); } static void user_window_mouse_move(Window *win, int x, int y, uint8_t buttons) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = GUI_EVENT_MOUSE_MOVE, .arg1 = x, .arg2 = y, .arg3 = buttons }; process_push_gui_event(proc, &ev); } // Helper function for WM to send mouse events void syscall_send_mouse_move_event(Window *win, int x, int y, uint8_t buttons) { if (!win) return; user_window_mouse_move(win, x, y, buttons); } void syscall_send_mouse_down_event(Window *win, int x, int y) { if (!win) return; user_window_mouse_down(win, x, y); } void syscall_send_mouse_up_event(Window *win, int x, int y) { if (!win) return; user_window_mouse_up(win, x, y); } static void user_window_key(Window *win, int legacy, uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed) { process_t *proc = process_get_by_ui_window(win); if (!proc) return; gui_event_t ev = { .type = pressed ? GUI_EVENT_KEY : GUI_EVENT_KEYUP, .arg1 = legacy, .arg2 = (int)keycode, .arg3 = (int)mods, .arg4 = (int)codepoint }; process_push_gui_event(proc, &ev); } static void user_window_resize(Window *win, int w, int h) { if (!win) return; if (w <= 0 || h <= 0) return; extern void* kmalloc(size_t size); extern void kfree(void* ptr); extern void serial_write(const char *str); if (win->pixels) kfree(win->pixels); if (win->comp_pixels) kfree(win->comp_pixels); win->pixels = (uint32_t *)kmalloc(w * h * sizeof(uint32_t)); win->comp_pixels = (uint32_t *)kmalloc(w * h * sizeof(uint32_t)); win->w = w; win->h = h; if (win->pixels) { extern void mem_memset(void *dest, int val, size_t len); mem_memset(win->pixels, 0, w * h * sizeof(uint32_t)); } process_t *proc = process_get_by_ui_window(win); if (proc) { gui_event_t ev = { .type = GUI_EVENT_RESIZE, .arg1 = w, .arg2 = h }; process_push_gui_event(proc, &ev); } } typedef struct { registers_t *regs; uint64_t arg1; uint64_t arg2; uint64_t arg3; uint64_t arg4; uint64_t arg5; } syscall_args_t; typedef uint64_t (*syscall_handler_fn)(const syscall_args_t *args); static uint64_t gui_cmd_window_create(const syscall_args_t *args) { extern void serial_write(const char *str); process_t *proc = process_get_current(); const char *title = (const char *)args->arg2; serial_write("[WM] CreateWindow: "); serial_write(title ? title : "Unknown"); serial_write("\n"); uint64_t *u_params = (uint64_t *)args->arg3; if (!u_params) { serial_write("[WM] Error - params is NULL\n"); return 0; } // Copy params from user space to kernel space for safety uint64_t params[4]; for (int i = 0; i < 4; i++) params[i] = u_params[i]; Window *win = kmalloc(sizeof(Window)); if (!win) { serial_write("[WM] Error - kmalloc failed for Window\n"); return 0; } extern void mem_memset(void *dest, int val, size_t len); mem_memset(win, 0, sizeof(Window)); // Copy title from user space to kernel space so wm.c can access it safely int title_len = 0; if (title) { while (title[title_len] && title_len < 255) title_len++; } char *kernel_title = kmalloc(title_len + 1); if (kernel_title) { for (int i = 0; i < title_len; i++) { kernel_title[i] = title[i]; } kernel_title[title_len] = '\0'; } else { serial_write("[WM] Warning: kernel_title kmalloc failed\n"); } // Basic initialization win->title = kernel_title ? kernel_title : "Unknown"; win->x = (int)params[0]; win->y = (int)params[1]; win->w = (int)params[2]; win->h = (int)params[3]; // Sanity checks for dimensions if (win->w <= 0 || win->w > 4096) win->w = 400; if (win->h <= 0 || win->h > 4096) win->h = 400; win->visible = true; win->focused = true; win->z_index = 0; win->cursor_pos = 0; win->data = proc; win->font = NULL; win->lock = SPINLOCK_INIT; size_t pixel_size = 0; // Safe allocation size_t client_h = win->h - 20; if (win->w <= 0 || win->h <= 20) { // Invalid dimensions, but prevent underflow/bad alloc win->pixels = NULL; win->comp_pixels = NULL; } else { pixel_size = (size_t)win->w * client_h * 4; win->pixels = kmalloc(pixel_size); win->comp_pixels = kmalloc(pixel_size); } if (win->pixels) { extern void mem_memset(void *dest, int val, size_t len); mem_memset(win->pixels, 0, pixel_size); } if (win->comp_pixels) { extern void mem_memset(void *dest, int val, size_t len); mem_memset(win->comp_pixels, 0, pixel_size); } serial_write("[WM] Buffers ready\n"); // Set callbacks win->paint = user_window_paint; win->handle_click = user_window_click; win->handle_right_click = user_window_right_click; win->handle_mouse_down = user_window_mouse_down; win->handle_mouse_up = user_window_mouse_up; win->handle_mouse_move = user_window_mouse_move; win->handle_close = user_window_close; win->handle_key = user_window_key; win->handle_resize = user_window_resize; win->resizable = false; // Default to false, can be enabled via syscall // Store owner PID to allow safe detachment during window destruction. // This prevents Use-After-Free when a process continues drawing after its window is closed. win->owner_pid = proc->pid; proc->ui_window = win; wm_add_window(win); wm_mark_dirty(0, 0, get_screen_width(), 30); return (uint64_t)win; } static uint64_t gui_cmd_draw_rect(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t *u_params = (uint64_t *)args->arg3; uint32_t color = (uint32_t)args->arg4; process_t *proc = process_get_current(); if (win && u_params && proc && proc->ui_window == win) { uint64_t params[4]; for (int i = 0; i < 4; i++) params[i] = u_params[i]; extern void draw_rect(int x, int y, int w, int h, uint32_t color); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); uint64_t rflags = spinlock_acquire_irqsave(&win->lock); if (win->pixels) { int rx = (int)params[0]; int ry = (int)params[1]; int rw = (int)params[2]; int rh = (int)params[3]; if (rx < 0) { rw += rx; rx = 0; } if (ry < 0) { rh += ry; ry = 0; } if (rx + rw > win->w) rw = win->w - rx; if (ry + rh > (win->h - 20)) rh = (win->h - 20) - ry; if (rw > 0 && rh > 0) { graphics_set_render_target(win->pixels, win->w, win->h - 20); draw_rect(rx, ry, rw, rh, color); graphics_set_render_target(NULL, 0, 0); } } else { uint64_t wflags = wm_lock_acquire(); draw_rect(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3], color); wm_lock_release(wflags); } spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_draw_rounded_rect_filled(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t *u_params = (uint64_t *)args->arg3; uint32_t color = (uint32_t)args->arg4; process_t *proc = process_get_current(); if (win && u_params && proc && proc->ui_window == win) { uint64_t params[5]; for (int i = 0; i < 5; i++) params[i] = u_params[i]; extern void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); uint64_t rflags = spinlock_acquire_irqsave(&win->lock); if (win->pixels) { int rx = (int)params[0]; int ry = (int)params[1]; int rw = (int)params[2]; int rh = (int)params[3]; int rr = (int)params[4]; if (rx < 0) { rw += rx; rx = 0; } if (ry < 0) { rh += ry; ry = 0; } if (rx + rw > win->w) rw = win->w - rx; if (ry + rh > (win->h - 20)) rh = (win->h - 20) - ry; if (rw > 0 && rh > 0) { graphics_set_render_target(win->pixels, win->w, win->h - 20); draw_rounded_rect_filled(rx, ry, rw, rh, rr, color); graphics_set_render_target(NULL, 0, 0); } } spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_draw_string(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t coords = args->arg3; int ux = coords & 0xFFFFFFFF; int uy = coords >> 32; const char *user_str = (const char *)args->arg4; uint32_t color = (uint32_t)args->arg5; process_t *proc = process_get_current(); if (win && user_str && proc && proc->ui_window == win) { extern void draw_string(int x, int y, const char *str, uint32_t color); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); // Copy string safely to kernel stack buffer char kernel_str[256]; int i = 0; while (i < 255 && user_str[i]) { kernel_str[i] = user_str[i]; i++; } kernel_str[i] = 0; uint64_t rflags = spinlock_acquire_irqsave(&win->lock); ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf(); if (win->pixels) { if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) { graphics_set_render_target(win->pixels, win->w, win->h - 20); if (font) { int baseline = uy + font_manager_get_font_ascent_scaled(font, font->pixel_height) - 2; int cur_x = ux; const char *s = kernel_str; int start_x = cur_x; while (*s) { uint32_t codepoint = utf8_decode(&s); if (codepoint == '\n') { cur_x = start_x; baseline += font_manager_get_font_line_height_scaled(font, font->pixel_height); } else if (codepoint == '\t') { cur_x += font_manager_get_codepoint_width_scaled(font, ' ', font->pixel_height) * 4; } else { font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, font->pixel_height, put_pixel); cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, font->pixel_height); } } } else { draw_string(ux, uy, kernel_str, color); } graphics_set_render_target(NULL, 0, 0); } } else { uint64_t wflags = wm_lock_acquire(); if (font) { int baseline = win->y + uy + font_manager_get_font_ascent_scaled(font, font->pixel_height) - 2; int cur_x = win->x + ux; const char *s = kernel_str; int start_x = cur_x; while (*s) { uint32_t codepoint = utf8_decode(&s); if (codepoint == '\n') { cur_x = start_x; baseline += font_manager_get_font_line_height_scaled(font, font->pixel_height); } else if (codepoint == '\t') { cur_x += font_manager_get_codepoint_width_scaled(font, ' ', font->pixel_height) * 4; } else { font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, font->pixel_height, put_pixel); cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, font->pixel_height); } } } else { draw_string(win->x + ux, win->y + uy, kernel_str, color); } wm_lock_release(wflags); } spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_draw_string_bitmap(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t coords = args->arg3; int ux = coords & 0xFFFFFFFF; int uy = coords >> 32; const char *user_str = (const char *)args->arg4; uint32_t color = (uint32_t)args->arg5; if (win && user_str) { extern void draw_string_bitmap(int x, int y, const char *str, uint32_t color); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); // Copy string safely to kernel stack buffer char kernel_str[256]; int i = 0; while (i < 255 && user_str[i]) { kernel_str[i] = user_str[i]; i++; } kernel_str[i] = 0; uint64_t rflags; bool use_wm_lock = (win->pixels == NULL); if (use_wm_lock) rflags = wm_lock_acquire(); else rflags = spinlock_acquire_irqsave(&win->lock); if (win->pixels) { if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) { graphics_set_render_target(win->pixels, win->w, win->h - 20); draw_string_bitmap(ux, uy, kernel_str, color); graphics_set_render_target(NULL, 0, 0); } } else { draw_string_bitmap(win->x + ux, win->y + uy, kernel_str, color); } if (use_wm_lock) wm_lock_release(rflags); else spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_draw_string_scaled(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t coords = args->arg3; int ux = coords & 0xFFFFFFFF; int uy = coords >> 32; const char *user_str = (const char *)args->arg4; uint64_t packed = args->arg5; uint32_t color = packed & 0xFFFFFFFF; uint32_t scale_bits = packed >> 32; float scale = *(float*)&scale_bits; if (win && user_str) { extern void draw_string_scaled(int x, int y, const char *str, uint32_t color, float scale); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); // Copy string safely to kernel stack buffer char kernel_str[256]; int i = 0; while (i < 255 && user_str[i]) { kernel_str[i] = user_str[i]; i++; } kernel_str[i] = 0; uint64_t rflags; bool use_wm_lock = (win->pixels == NULL); if (use_wm_lock) rflags = wm_lock_acquire(); else rflags = spinlock_acquire_irqsave(&win->lock); ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf(); if (win->pixels) { if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) { graphics_set_render_target(win->pixels, win->w, win->h - 20); if (font) { int baseline = uy + font_manager_get_font_ascent_scaled(font, scale) - 2; int cur_x = ux; const char *s = kernel_str; int start_x = cur_x; while (*s) { uint32_t codepoint = utf8_decode(&s); if (codepoint == '\n') { cur_x = start_x; baseline += font_manager_get_font_line_height_scaled(font, scale); } else if (codepoint == '\t') { cur_x += font_manager_get_codepoint_width_scaled(font, ' ', scale) * 4; } else { font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, scale, put_pixel); cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } } else { draw_string_scaled(ux, uy, kernel_str, color, scale); } graphics_set_render_target(NULL, 0, 0); } } else { if (font) { int baseline = win->y + uy + font_manager_get_font_ascent_scaled(font, scale) - 2; int cur_x = win->x + ux; const char *s = kernel_str; int start_x = cur_x; while (*s) { uint32_t codepoint = utf8_decode(&s); if (codepoint == '\n') { cur_x = start_x; baseline += font_manager_get_font_line_height_scaled(font, scale); } else if (codepoint == '\t') { cur_x += font_manager_get_codepoint_width_scaled(font, ' ', scale) * 4; } else { font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, scale, put_pixel); cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } } else { draw_string_scaled(win->x + ux, win->y + uy, kernel_str, color, scale); } } if (use_wm_lock) wm_lock_release(rflags); else spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_draw_string_scaled_sloped(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t coords = args->arg3; int ux = coords & 0xFFFFFFFF; int uy = coords >> 32; const char *user_str = (const char *)args->arg4; // Unpack color, scale, slope from arg5 uint64_t packed1 = args->arg5; uint32_t color = packed1 & 0xFFFFFFFF; uint32_t scale_bits = packed1 >> 32; float scale = *(float*)&scale_bits; uint64_t arg6 = args->regs->r9; uint32_t slope_bits = arg6 & 0xFFFFFFFF; float slope = *(float*)&slope_bits; if (win && user_str) { extern void draw_string_scaled_sloped(int x, int y, const char *str, uint32_t color, float scale, float slope); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); // Copy string safely to kernel stack buffer char kernel_str[256]; int i = 0; while (i < 255 && user_str[i]) { kernel_str[i] = user_str[i]; i++; } kernel_str[i] = 0; uint64_t rflags; bool use_wm_lock = (win->pixels == NULL); if (use_wm_lock) rflags = wm_lock_acquire(); else rflags = spinlock_acquire_irqsave(&win->lock); ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf(); if (win->pixels) { if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) { graphics_set_render_target(win->pixels, win->w, win->h - 20); if (font) { int baseline = uy + font_manager_get_font_ascent_scaled(font, scale) - 2; int cur_x = ux; const char *s = kernel_str; int start_x = cur_x; while (*s) { extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); uint32_t codepoint = utf8_decode(&s); if (codepoint == '\n') { cur_x = start_x; baseline += font_manager_get_font_line_height_scaled(font, scale); } else if (codepoint == '\t') { cur_x += font_manager_get_codepoint_width_scaled(font, ' ', scale) * 4; } else { font_manager_render_char_sloped(font, cur_x, baseline, codepoint, color, scale, slope, put_pixel); cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } } else { draw_string_scaled_sloped(ux, uy, kernel_str, color, scale, slope); } graphics_set_render_target(NULL, 0, 0); } } else { if (font) { int baseline = win->y + uy + font_manager_get_font_ascent_scaled(font, scale) - 2; int cur_x = win->x + ux; const char *s = kernel_str; int start_x = cur_x; while (*s) { extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); uint32_t codepoint = utf8_decode(&s); if (codepoint == '\n') { cur_x = start_x; baseline += font_manager_get_font_line_height_scaled(font, scale); } else if (codepoint == '\t') { cur_x += font_manager_get_codepoint_width_scaled(font, ' ', scale) * 4; } else { font_manager_render_char_sloped(font, cur_x, baseline, codepoint, color, scale, slope, put_pixel); cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } } else { draw_string_scaled_sloped(win->x + ux, win->y + uy, kernel_str, color, scale, slope); } } if (use_wm_lock) wm_lock_release(rflags); else spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_draw_image(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t *u_params = (uint64_t *)args->arg3; uint32_t *image_data = (uint32_t *)args->arg4; process_t *proc = process_get_current(); if (win && u_params && image_data && proc && proc->ui_window == win) { uint64_t params[4]; for (int i = 0; i < 4; i++) params[i] = u_params[i]; uint64_t rflags = spinlock_acquire_irqsave(&win->lock); if (win->pixels) { int rx = (int)params[0]; int ry = (int)params[1]; int rw = (int)params[2]; int rh = (int)params[3]; int src_w = rw; int src_x_offset = 0; int src_y_offset = 0; if (rx < 0) { src_x_offset = -rx; rw += rx; rx = 0; } if (ry < 0) { src_y_offset = -ry; rh += ry; ry = 0; } if (rx + rw > win->w) rw = win->w - rx; if (ry + rh > (win->h - 20)) rh = (win->h - 20) - ry; if (rw > 0 && rh > 0) { for (int y = 0; y < rh; y++) { uint32_t *dest = &win->pixels[(ry + y) * win->w + rx]; uint32_t *src = &image_data[(src_y_offset + y) * src_w + src_x_offset]; for (int x = 0; x < rw; x++) { uint32_t s = src[x]; uint8_t alpha = (s >> 24) & 0xFF; if (alpha == 0xFF) { dest[x] = s; } else if (alpha > 0) { uint32_t d = dest[x]; uint32_t rb = ((s & 0xFF00FF) * alpha + (d & 0xFF00FF) * (255 - alpha)) >> 8; uint32_t g = ((s & 0x00FF00) * alpha + (d & 0x00FF00) * (255 - alpha)) >> 8; dest[x] = (rb & 0xFF00FF) | (g & 0x00FF00) | 0xFF000000; } } } } } spinlock_release_irqrestore(&win->lock, rflags); } return 0; } static uint64_t gui_cmd_mark_dirty(const syscall_args_t *args) { Window *win = (Window *)args->arg2; uint64_t *u_params = (uint64_t *)args->arg3; process_t *proc = process_get_current(); if (win && u_params && proc && proc->ui_window == win) { uint64_t params[4]; for (int i = 0; i < 4; i++) params[i] = u_params[i]; // Dual-buffer commit: copy pixels to comp_pixels if (win->pixels && win->comp_pixels) { uint64_t win_rflags = spinlock_acquire_irqsave(&win->lock); extern void mem_memcpy(void *dest, const void *src, size_t len); mem_memcpy(win->comp_pixels, win->pixels, (size_t)win->w * (win->h - 20) * 4); spinlock_release_irqrestore(&win->lock, win_rflags); } uint64_t rflags = wm_lock_acquire(); wm_mark_dirty(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3]); wm_lock_release(rflags); } return 0; } static uint64_t gui_cmd_get_event(const syscall_args_t *args) { process_t *proc = process_get_current(); gui_event_t *ev_out = (gui_event_t *)args->arg3; if (!ev_out) return 0; if (proc->gui_event_head != proc->gui_event_tail) { *ev_out = proc->gui_events[proc->gui_event_head]; proc->gui_event_head = (proc->gui_event_head + 1) % MAX_GUI_EVENTS; return 1; } return 0; } static uint64_t gui_cmd_get_string_width(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *user_str = (const char *)args->arg2; if (!user_str) return 0; char kernel_str[256]; int i = 0; while (i < 255 && user_str[i]) { kernel_str[i] = user_str[i]; i++; } kernel_str[i] = 0; ttf_font_t *font = (proc->ui_window && ((Window*)proc->ui_window)->font) ? (ttf_font_t*)((Window*)proc->ui_window)->font : graphics_get_current_ttf(); if (font) { return (uint64_t)font_manager_get_string_width_scaled(font, kernel_str, font->pixel_height); } else { return (uint64_t)i * 8; // Fallback bitmap width } } static uint64_t gui_cmd_get_font_height(const syscall_args_t *args) { process_t *proc = process_get_current(); ttf_font_t *font = (proc->ui_window && ((Window*)proc->ui_window)->font) ? (ttf_font_t*)((Window*)proc->ui_window)->font : graphics_get_current_ttf(); if (font) { return (uint64_t)font_manager_get_font_height_scaled(font, font->pixel_height); } return 10; } static uint64_t gui_cmd_get_string_width_scaled(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *user_str = (const char *)args->arg2; uint32_t scale_bits = (uint32_t)args->arg3; float scale = *(float*)&scale_bits; if (!user_str) return 0; char kernel_str[256]; int i = 0; while (i < 255 && user_str[i]) { kernel_str[i] = user_str[i]; i++; } kernel_str[i] = 0; extern int graphics_get_string_width_scaled(const char *s, float scale); ttf_font_t *font = (proc->ui_window && ((Window*)proc->ui_window)->font) ? (ttf_font_t*)((Window*)proc->ui_window)->font : graphics_get_current_ttf(); if (font) { return (uint64_t)font_manager_get_string_width_scaled(font, kernel_str, scale); } else { return (uint64_t)i * 8; // Fallback } } static uint64_t gui_cmd_get_font_height_scaled(const syscall_args_t *args) { process_t *proc = process_get_current(); uint32_t scale_bits = (uint32_t)args->arg2; float scale = *(float*)&scale_bits; ttf_font_t *font = (proc->ui_window && ((Window*)proc->ui_window)->font) ? (ttf_font_t*)((Window*)proc->ui_window)->font : graphics_get_current_ttf(); if (font) { return (uint64_t)font_manager_get_font_height_scaled(font, scale); } return 10; } static uint64_t gui_cmd_window_set_resizable(const syscall_args_t *args) { Window *win = (Window *)args->arg2; process_t *proc = process_get_current(); if (win && proc && proc->ui_window == win) { uint64_t flags = spinlock_acquire_irqsave(&win->lock); win->resizable = (args->arg3 != 0); spinlock_release_irqrestore(&win->lock, flags); extern void serial_write(const char *str); serial_write("[WM] Resizable: "); serial_write(args->arg3 ? "true\n" : "false\n"); } return 0; } static uint64_t gui_cmd_window_set_title(const syscall_args_t *args) { Window *win = (Window *)args->arg2; const char *user_title = (const char *)args->arg3; process_t *proc = process_get_current(); if (win && user_title && proc && proc->ui_window == win) { int title_len = 0; while (user_title[title_len] && title_len < 255) title_len++; char *kernel_title = kmalloc(title_len + 1); if (kernel_title) { for (int i = 0; i < title_len; i++) { kernel_title[i] = user_title[i]; } kernel_title[title_len] = '\0'; uint64_t flags = spinlock_acquire_irqsave(&win->lock); char *old_title = win->title; win->title = kernel_title; spinlock_release_irqrestore(&win->lock, flags); if (old_title && old_title != (char*)"Unknown") { kfree(old_title); } wm_mark_dirty(win->x, win->y - 20, win->w, 20); // Mark title bar dirty wm_refresh(); } } return 0; } static uint64_t gui_cmd_set_font(const syscall_args_t *args) { Window *win = (Window *)args->arg2; const char *user_path = (const char *)args->arg3; if (win && user_path) { char kernel_path[256]; int i = 0; while (i < 255 && user_path[i]) { kernel_path[i] = user_path[i]; i++; } kernel_path[i] = 0; ttf_font_t *new_font = font_manager_load(kernel_path, 15.0f); if (new_font) { win->font = new_font; } } return 0; } static uint64_t gui_cmd_get_screen_size(const syscall_args_t *args) { uint64_t *out_w = (uint64_t *)args->arg2; uint64_t *out_h = (uint64_t *)args->arg3; if (out_w && out_h) { extern int get_screen_width(void); extern int get_screen_height(void); *out_w = (uint64_t)get_screen_width(); *out_h = (uint64_t)get_screen_height(); } return 0; } static uint64_t gui_cmd_get_screenbuffer(const syscall_args_t *args) { uint32_t *dest = (uint32_t *)args->arg2; if (dest) { extern void graphics_copy_screenbuffer(uint32_t *dest); graphics_copy_screenbuffer(dest); } return 0; } static uint64_t gui_cmd_show_notification(const syscall_args_t *args) { const char *user_msg = (const char *)args->arg2; if (user_msg) { char kernel_msg[256]; int i = 0; while (i < 255 && user_msg[i]) { kernel_msg[i] = user_msg[i]; i++; } kernel_msg[i] = 0; extern void wm_show_notification(const char *msg); wm_show_notification(kernel_msg); } return 0; } static uint64_t gui_cmd_get_datetime(const syscall_args_t *args) { uint64_t *out_arr = (uint64_t *)args->arg2; if (out_arr) { extern void rtc_get_datetime(int *year, int *month, int *day, int *hour, int *minute, int *second); int y, m, d, h, min, s; rtc_get_datetime(&y, &m, &d, &h, &min, &s); out_arr[0] = y; out_arr[1] = m; out_arr[2] = d; out_arr[3] = h; out_arr[4] = min; out_arr[5] = s; } return 0; } #define GUI_CMD_TABLE_SIZE 54 static const syscall_handler_fn gui_cmd_table[GUI_CMD_TABLE_SIZE] = { [GUI_CMD_WINDOW_CREATE] = gui_cmd_window_create, [GUI_CMD_DRAW_RECT] = gui_cmd_draw_rect, [GUI_CMD_DRAW_STRING] = gui_cmd_draw_string, [GUI_CMD_MARK_DIRTY] = gui_cmd_mark_dirty, [GUI_CMD_GET_EVENT] = gui_cmd_get_event, [GUI_CMD_DRAW_ROUNDED_RECT_FILLED] = gui_cmd_draw_rounded_rect_filled, [GUI_CMD_DRAW_IMAGE] = gui_cmd_draw_image, [GUI_CMD_GET_STRING_WIDTH] = gui_cmd_get_string_width, [GUI_CMD_GET_FONT_HEIGHT] = gui_cmd_get_font_height, [10] = gui_cmd_draw_string_bitmap, [11] = gui_cmd_draw_string_scaled, [12] = gui_cmd_get_string_width_scaled, [13] = gui_cmd_get_font_height_scaled, [GUI_CMD_WINDOW_SET_RESIZABLE] = gui_cmd_window_set_resizable, [15] = gui_cmd_window_set_title, [16] = gui_cmd_set_font, [18] = gui_cmd_draw_string_scaled_sloped, [GUI_CMD_GET_SCREEN_SIZE] = gui_cmd_get_screen_size, [GUI_CMD_GET_SCREENBUFFER] = gui_cmd_get_screenbuffer, [GUI_CMD_SHOW_NOTIFICATION] = gui_cmd_show_notification, [GUI_CMD_GET_DATETIME] = gui_cmd_get_datetime, }; #define O_RDONLY 0x0000 #define O_WRONLY 0x0001 #define O_RDWR 0x0002 #define O_APPEND 0x0400 #define O_NONBLOCK 0x0800 #define F_GETFL 3 #define F_SETFL 4 static int fs_alloc_fd_slot(process_t *proc, int start) { for (int i = start; i < MAX_PROCESS_FDS; i++) { if (!proc->fds[i]) return i; } return -1; } static int fs_mode_to_flags(const char *mode) { if (!mode || !mode[0]) return O_RDONLY; if (mode[0] == 'r') { return (mode[1] == '+') ? O_RDWR : O_RDONLY; } if (mode[0] == 'a') { return (mode[1] == '+') ? (O_RDWR | O_APPEND) : (O_WRONLY | O_APPEND); } if (mode[0] == 'w') { return (mode[1] == '+') ? O_RDWR : O_WRONLY; } return O_RDONLY; } static uint64_t fs_cmd_open(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *path = (const char *)args->arg2; const char *mode = (const char *)args->arg3; if (!path || !mode) return -1; // vfs_open now handles normalization internally with process_get_current() // but let's be explicit if we can. vfs_file_t *vf = vfs_open(path, mode); if (!vf) return -1; process_fd_file_ref_t *ref = (process_fd_file_ref_t *)kmalloc(sizeof(process_fd_file_ref_t)); if (!ref) { vfs_close(vf); return -1; } ref->file = vf; ref->refs = 1; for (int i = 0; i < MAX_PROCESS_FDS; i++) { if (proc->fds[i] == NULL) { proc->fds[i] = ref; proc->fd_kind[i] = PROC_FD_KIND_FILE; proc->fd_flags[i] = fs_mode_to_flags(mode); return (uint64_t)i; } } kfree(ref); vfs_close(vf); return -1; } static uint64_t fs_cmd_read(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; void *buf = (void *)args->arg3; uint32_t len = (uint32_t)args->arg4; if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (proc->fd_kind[fd] == PROC_FD_KIND_FILE) { process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[fd]; if (!ref || !ref->file) return -1; return (uint64_t)vfs_read(ref->file, buf, (int)len); } if (proc->fd_kind[fd] == PROC_FD_KIND_PIPE_READ) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[fd]; if (!pipe || !buf) return -1; uint8_t *out = (uint8_t *)buf; uint32_t n = 0; while (n < len) { if (pipe->count == 0) { if (pipe->writers == 0) break; if (proc->fd_flags[fd] & O_NONBLOCK) { if (n == 0) return (uint64_t)-1; break; } break; } out[n++] = pipe->data[pipe->read_pos]; pipe->read_pos = (pipe->read_pos + 1) % sizeof(pipe->data); pipe->count--; } return n; } return -1; } static uint64_t fs_cmd_write(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; const void *buf = (const void *)args->arg3; uint32_t len = (uint32_t)args->arg4; if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (proc->fd_kind[fd] == PROC_FD_KIND_FILE) { process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[fd]; if (!ref || !ref->file) return -1; return (uint64_t)vfs_write(ref->file, buf, (int)len); } if (proc->fd_kind[fd] == PROC_FD_KIND_PIPE_WRITE) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[fd]; if (!pipe || !buf) return -1; if (pipe->readers <= 0) return (uint64_t)-1; const uint8_t *in = (const uint8_t *)buf; uint32_t n = 0; while (n < len) { if (pipe->count == sizeof(pipe->data)) { if (proc->fd_flags[fd] & O_NONBLOCK) { if (n == 0) return (uint64_t)-1; break; } break; } pipe->data[pipe->write_pos] = in[n++]; pipe->write_pos = (pipe->write_pos + 1) % sizeof(pipe->data); pipe->count++; } return n; } return -1; } static uint64_t fs_cmd_close(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (proc->fd_kind[fd] == PROC_FD_KIND_FILE) { process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[fd]; if (ref) { ref->refs--; if (ref->refs <= 0) { if (ref->file) vfs_close(ref->file); kfree(ref); } } } else if (proc->fd_kind[fd] == PROC_FD_KIND_PIPE_READ || proc->fd_kind[fd] == PROC_FD_KIND_PIPE_WRITE) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[fd]; if (pipe) { if (proc->fd_kind[fd] == PROC_FD_KIND_PIPE_READ) pipe->readers--; else pipe->writers--; if (pipe->readers <= 0 && pipe->writers <= 0) { kfree(pipe); } } } proc->fds[fd] = NULL; proc->fd_kind[fd] = PROC_FD_KIND_NONE; proc->fd_flags[fd] = 0; return 0; } static uint64_t fs_cmd_seek(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; int offset = (int)args->arg3; int whence = (int)args->arg4; // 0=SET, 1=CUR, 2=END if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (proc->fd_kind[fd] != PROC_FD_KIND_FILE) return -1; process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[fd]; if (!ref || !ref->file) return -1; return (uint64_t)vfs_seek(ref->file, offset, whence); } static uint64_t fs_cmd_tell(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (proc->fd_kind[fd] == PROC_FD_KIND_PIPE_READ || proc->fd_kind[fd] == PROC_FD_KIND_PIPE_WRITE) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[fd]; return pipe ? pipe->count : 0; } if (proc->fd_kind[fd] != PROC_FD_KIND_FILE) return -1; process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[fd]; if (!ref || !ref->file) return -1; return (uint64_t)vfs_file_position(ref->file); } static uint64_t fs_cmd_size(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (proc->fd_kind[fd] == PROC_FD_KIND_PIPE_READ || proc->fd_kind[fd] == PROC_FD_KIND_PIPE_WRITE) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[fd]; return pipe ? pipe->count : 0; } if (proc->fd_kind[fd] != PROC_FD_KIND_FILE) return -1; process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[fd]; if (!ref || !ref->file) return -1; return (uint64_t)vfs_file_size(ref->file); } static uint64_t fs_cmd_dup(const syscall_args_t *args) { process_t *proc = process_get_current(); int oldfd = (int)args->arg2; if (oldfd < 0 || oldfd >= MAX_PROCESS_FDS || !proc->fds[oldfd]) return -1; int newfd = fs_alloc_fd_slot(proc, 0); if (newfd < 0) return -1; proc->fds[newfd] = proc->fds[oldfd]; proc->fd_kind[newfd] = proc->fd_kind[oldfd]; proc->fd_flags[newfd] = proc->fd_flags[oldfd]; if (proc->fd_kind[oldfd] == PROC_FD_KIND_FILE) { process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[oldfd]; if (ref) ref->refs++; } else if (proc->fd_kind[oldfd] == PROC_FD_KIND_PIPE_READ) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[oldfd]; if (pipe) pipe->readers++; } else if (proc->fd_kind[oldfd] == PROC_FD_KIND_PIPE_WRITE) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[oldfd]; if (pipe) pipe->writers++; } return (uint64_t)newfd; } static uint64_t fs_cmd_dup2(const syscall_args_t *args) { process_t *proc = process_get_current(); int oldfd = (int)args->arg2; int newfd = (int)args->arg3; if (oldfd < 0 || oldfd >= MAX_PROCESS_FDS || !proc->fds[oldfd]) return -1; if (newfd < 0 || newfd >= MAX_PROCESS_FDS) return -1; if (oldfd == newfd) return (uint64_t)newfd; if (proc->fds[newfd]) { syscall_args_t close_args = *args; close_args.arg2 = (uint64_t)newfd; if (fs_cmd_close(&close_args) != 0) return -1; } proc->fds[newfd] = proc->fds[oldfd]; proc->fd_kind[newfd] = proc->fd_kind[oldfd]; proc->fd_flags[newfd] = proc->fd_flags[oldfd]; if (proc->fd_kind[oldfd] == PROC_FD_KIND_FILE) { process_fd_file_ref_t *ref = (process_fd_file_ref_t *)proc->fds[oldfd]; if (ref) ref->refs++; } else if (proc->fd_kind[oldfd] == PROC_FD_KIND_PIPE_READ) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[oldfd]; if (pipe) pipe->readers++; } else if (proc->fd_kind[oldfd] == PROC_FD_KIND_PIPE_WRITE) { process_fd_pipe_t *pipe = (process_fd_pipe_t *)proc->fds[oldfd]; if (pipe) pipe->writers++; } return (uint64_t)newfd; } static uint64_t fs_cmd_pipe(const syscall_args_t *args) { process_t *proc = process_get_current(); int *pipefd = (int *)args->arg2; if (!pipefd) return -1; int rfd = fs_alloc_fd_slot(proc, 0); if (rfd < 0) return -1; int wfd = fs_alloc_fd_slot(proc, rfd + 1); if (wfd < 0) return -1; process_fd_pipe_t *pipe = (process_fd_pipe_t *)kmalloc(sizeof(process_fd_pipe_t)); if (!pipe) return -1; mem_memset(pipe, 0, sizeof(*pipe)); pipe->readers = 1; pipe->writers = 1; proc->fds[rfd] = pipe; proc->fd_kind[rfd] = PROC_FD_KIND_PIPE_READ; proc->fd_flags[rfd] = O_RDONLY; proc->fds[wfd] = pipe; proc->fd_kind[wfd] = PROC_FD_KIND_PIPE_WRITE; proc->fd_flags[wfd] = O_WRONLY; pipefd[0] = rfd; pipefd[1] = wfd; return 0; } static uint64_t fs_cmd_fcntl(const syscall_args_t *args) { process_t *proc = process_get_current(); int fd = (int)args->arg2; int cmd = (int)args->arg3; int val = (int)args->arg4; if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; if (cmd == F_GETFL) { return (uint64_t)proc->fd_flags[fd]; } if (cmd == F_SETFL) { proc->fd_flags[fd] = (proc->fd_flags[fd] & ~(O_APPEND | O_NONBLOCK)) | (val & (O_APPEND | O_NONBLOCK)); return 0; } return -1; } static uint64_t fs_cmd_list(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *path = (const char *)args->arg2; FAT32_FileInfo *u_entries = (FAT32_FileInfo *)args->arg3; int max_entries = (int)args->arg4; if (!path || !u_entries) return -1; char normalized[VFS_MAX_PATH]; vfs_normalize_path(proc->cwd, path, normalized); // Safety cap for kernel allocation if (max_entries > 256) max_entries = 256; if (max_entries <= 0) return 0; vfs_dirent_t *v_entries = (vfs_dirent_t *)kmalloc(sizeof(vfs_dirent_t) * max_entries); if (!v_entries) return -1; int count = vfs_list_directory(normalized, v_entries, max_entries); if (count > 0) { for (int i = 0; i < count; i++) { // Direct copy as layouts are now aligned strcpy(u_entries[i].name, v_entries[i].name); u_entries[i].size = v_entries[i].size; u_entries[i].is_directory = v_entries[i].is_directory; u_entries[i].start_cluster = v_entries[i].start_cluster; u_entries[i].write_date = v_entries[i].write_date; u_entries[i].write_time = v_entries[i].write_time; } } kfree(v_entries); return (uint64_t)count; } static uint64_t fs_cmd_delete(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *path = (const char *)args->arg2; if (!path) return -1; char normalized[VFS_MAX_PATH]; vfs_normalize_path(proc->cwd, path, normalized); return vfs_delete(normalized) ? 0 : -1; } static uint64_t fs_cmd_get_info(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *path = (const char *)args->arg2; FAT32_FileInfo *u_info = (FAT32_FileInfo *)args->arg3; if (!path || !u_info) return -1; char normalized[VFS_MAX_PATH]; vfs_normalize_path(proc->cwd, path, normalized); vfs_dirent_t v_info; int res = vfs_get_info(normalized, &v_info); if (res == 0) { strcpy(u_info->name, v_info.name); u_info->size = v_info.size; u_info->is_directory = v_info.is_directory; u_info->start_cluster = v_info.start_cluster; u_info->write_date = v_info.write_date; u_info->write_time = v_info.write_time; } return (uint64_t)res; } static uint64_t fs_cmd_mkdir(const syscall_args_t *args) { const char *path = (const char *)args->arg2; if (!path) return -1; return vfs_mkdir(path) ? 0 : -1; } static uint64_t fs_cmd_exists(const syscall_args_t *args) { const char *path = (const char *)args->arg2; if (!path) return 0; return vfs_exists(path) ? 1 : 0; } static uint64_t fs_cmd_getcwd(const syscall_args_t *args) { process_t *proc = process_get_current(); char *buf = (char *)args->arg2; int size = (int)args->arg3; if (!buf || size <= 0) return -1; int len = (int)strlen(proc->cwd); if (len >= size) return -1; strcpy(buf, proc->cwd); return (uint64_t)len; } static uint64_t fs_cmd_chdir(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *path = (const char *)args->arg2; if (!path) return -1; char normalized[VFS_MAX_PATH]; vfs_normalize_path(proc->cwd, path, normalized); if (vfs_is_directory(normalized)) { strcpy(proc->cwd, normalized); return 0; } return -1; } static uint64_t fs_cmd_statfs(const syscall_args_t *args) { const char *path = (const char *)args->arg2; vfs_statfs_t *stat = (vfs_statfs_t *)args->arg3; if (!path || !stat) return -1; return vfs_statfs(path, stat) == 0 ? 0 : -1; } static uint64_t fs_cmd_mount_count(const syscall_args_t *args) { (void)args; return (uint64_t)vfs_get_mount_count(); } typedef struct { char path[256]; char device[32]; char fs_type[16]; } syscall_mount_info_t; static uint64_t fs_cmd_mount_info(const syscall_args_t *args) { int index = (int)args->arg2; syscall_mount_info_t *info = (syscall_mount_info_t *)args->arg3; if (!info) return -1; vfs_mount_t *m = vfs_get_mount(index); if (!m) return -1; strcpy(info->path, m->path); strcpy(info->device, m->device); strcpy(info->fs_type, m->fs_type); return 0; } #define FS_CMD_TABLE_SIZE 22 static const syscall_handler_fn fs_cmd_table[FS_CMD_TABLE_SIZE] = { [FS_CMD_OPEN] = fs_cmd_open, // 1 [FS_CMD_READ] = fs_cmd_read, // 2 [FS_CMD_WRITE] = fs_cmd_write, // 3 [FS_CMD_CLOSE] = fs_cmd_close, // 4 [FS_CMD_SEEK] = fs_cmd_seek, // 5 [FS_CMD_TELL] = fs_cmd_tell, // 6 [FS_CMD_LIST] = fs_cmd_list, // 7 [FS_CMD_DELETE] = fs_cmd_delete, // 8 [FS_CMD_SIZE] = fs_cmd_size, // 9 [FS_CMD_MKDIR] = fs_cmd_mkdir, // 10 [FS_CMD_EXISTS] = fs_cmd_exists, // 11 [FS_CMD_GETCWD] = fs_cmd_getcwd, // 12 [FS_CMD_CHDIR] = fs_cmd_chdir, // 13 [FS_CMD_GET_INFO] = fs_cmd_get_info, // 14 [FS_CMD_DUP] = fs_cmd_dup, // 15 [FS_CMD_DUP2] = fs_cmd_dup2, // 16 [FS_CMD_PIPE] = fs_cmd_pipe, // 17 [FS_CMD_FCNTL] = fs_cmd_fcntl, // 18 [FS_CMD_STATFS] = fs_cmd_statfs, // 19 [FS_CMD_MOUNT_COUNT] = fs_cmd_mount_count, // 20 [FS_CMD_MOUNT_INFO] = fs_cmd_mount_info, // 21 }; static uint64_t sys_cmd_set_bg_color(const syscall_args_t *args) { uint32_t color = (uint32_t)args->arg2; extern void graphics_set_bg_color(uint32_t color); graphics_set_bg_color(color); return 0; } static uint64_t sys_cmd_set_bg_pattern(const syscall_args_t *args) { uint32_t *user_pat = (uint32_t *)args->arg2; if (!user_pat) { graphics_set_bg_pattern(NULL); } else { static uint32_t global_bg_pattern[128*128]; for (int i=0; i<128*128; i++) { global_bg_pattern[i] = user_pat[i]; } graphics_set_bg_pattern(global_bg_pattern); } extern void wm_refresh(void); wm_refresh(); return 0; } static uint64_t sys_cmd_set_wallpaper(const syscall_args_t *args) { (void)args; return -1; } static uint64_t sys_cmd_set_desktop_prop(const syscall_args_t *args) { int prop = (int)args->arg2; int val = (int)args->arg3; extern _Bool desktop_snap_to_grid; extern _Bool desktop_auto_align; extern int desktop_max_rows_per_col; extern int desktop_max_cols; if (prop == 1) desktop_snap_to_grid = val; if (prop == 2) desktop_auto_align = val; if (prop == 3) desktop_max_rows_per_col = val; if (prop == 4) desktop_max_cols = val; extern void wm_refresh_desktop(void); wm_refresh_desktop(); return 0; } static uint64_t sys_cmd_set_mouse_speed(const syscall_args_t *args) { extern int mouse_speed; mouse_speed = (int)args->arg2; return 0; } static uint64_t sys_cmd_set_mouse_cursor_scale(const syscall_args_t *args) { wm_set_cursor_scale_tenths((int)args->arg2); return 0; } static uint64_t sys_cmd_network_init(const syscall_args_t *args) { (void)args; extern int network_init(void); return network_init(); } static uint64_t sys_cmd_get_desktop_prop(const syscall_args_t *args) { int prop = (int)args->arg2; extern _Bool desktop_snap_to_grid; extern _Bool desktop_auto_align; extern int desktop_max_rows_per_col; extern int desktop_max_cols; if (prop == 1) return desktop_snap_to_grid; if (prop == 2) return desktop_auto_align; if (prop == 3) return desktop_max_rows_per_col; if (prop == 4) return desktop_max_cols; return 0; } static uint64_t sys_cmd_get_mouse_speed(const syscall_args_t *args) { (void)args; extern int mouse_speed; return mouse_speed; } static uint64_t sys_cmd_get_mouse_cursor_scale(const syscall_args_t *args) { (void)args; return (uint64_t)wm_get_cursor_scale_tenths(); } static uint64_t sys_cmd_get_wallpaper_thumb(const syscall_args_t *args) { (void)args; return -1; } static uint64_t sys_cmd_clear_screen(const syscall_args_t *args) { (void)args; extern void cmd_screen_clear(void); cmd_screen_clear(); return 0; } static uint64_t sys_cmd_rtc_get(const syscall_args_t *args) { int *dt = (int *)args->arg2; if (!dt) return -1; extern void rtc_get_datetime(int *y, int *m, int *d, int *h, int *min, int *s); rtc_get_datetime(&dt[0], &dt[1], &dt[2], &dt[3], &dt[4], &dt[5]); return 0; } static uint64_t sys_cmd_reboot(const syscall_args_t *args) { (void)args; k_reboot(); return 0; } static uint64_t sys_cmd_shutdown(const syscall_args_t *args) { (void)args; k_shutdown(); return 0; } static uint64_t sys_cmd_beep(const syscall_args_t *args) { int freq = (int)args->arg2; int ms = (int)args->arg3; extern void k_beep(int freq, int ms); k_beep(freq, ms); return 0; } static uint64_t sys_cmd_get_mem_info(const syscall_args_t *args) { uint64_t *out = (uint64_t *)args->arg2; if (!out) return -1; MemStats stats = memory_get_stats(); out[0] = (uint64_t)stats.total_memory; out[1] = (uint64_t)stats.used_memory; return 0; } static uint64_t sys_cmd_get_ticks(const syscall_args_t *args) { (void)args; extern uint32_t wm_get_ticks(void); return (uint64_t)wm_get_ticks(); } static uint64_t sys_cmd_pci_list(const syscall_args_t *args) { typedef struct { uint16_t vendor; uint16_t device; uint8_t class_code; uint8_t subclass; } pci_info_t; pci_info_t *info = (pci_info_t *)args->arg2; int idx = (int)args->arg3; if (!info) { pci_device_t pci_devs[128]; return pci_enumerate_devices(pci_devs, 128); } pci_device_t pci_devs[128]; int count = pci_enumerate_devices(pci_devs, 128); if (idx >= 0 && idx < count) { info->vendor = pci_devs[idx].vendor_id; info->device = pci_devs[idx].device_id; info->class_code = pci_devs[idx].class_code; info->subclass = pci_devs[idx].subclass; return 0; } return -1; } static uint64_t sys_cmd_network_dhcp(const syscall_args_t *args) { (void)args; return network_dhcp_acquire(); } static uint64_t sys_cmd_network_get_mac(const syscall_args_t *args) { mac_address_t *mac = (mac_address_t *)args->arg2; if (!mac) return -1; return network_get_mac_address(mac); } static uint64_t sys_cmd_network_get_ip(const syscall_args_t *args) { ipv4_address_t *ip = (ipv4_address_t *)args->arg2; if (!ip) return -1; return network_get_ipv4_address(ip); } static uint64_t sys_cmd_network_set_ip(const syscall_args_t *args) { ipv4_address_t *ip = (ipv4_address_t *)args->arg2; if (!ip) return -1; return network_set_ipv4_address(ip); } static uint64_t sys_cmd_udp_send(const syscall_args_t *args) { ipv4_address_t *dest_ip = (ipv4_address_t *)args->arg2; uint32_t ports = (uint32_t)args->arg3; uint16_t dest_port = ports & 0xFFFF; uint16_t src_port = (ports >> 16) & 0xFFFF; const void *data = (const void *)args->arg4; size_t data_len = (size_t)args->arg5; if (!dest_ip || !data) return -1; return udp_send_packet(dest_ip, dest_port, src_port, data, data_len); } static uint64_t sys_cmd_network_get_stats(const syscall_args_t *args) { int stat_type = (int)args->arg2; switch (stat_type) { case 0: return network_get_frames_received(); case 1: return network_get_udp_packets_received(); case 2: return network_get_frames_sent(); case 3: return network_get_e1000_receive_calls(); case 4: return network_get_e1000_receive_empty(); case 5: return network_get_process_calls(); default: return -1; } } static uint64_t sys_cmd_network_get_gateway(const syscall_args_t *args) { ipv4_address_t *ip = (ipv4_address_t *)args->arg2; if (!ip) return -1; return network_get_gateway_ip(ip); } static uint64_t sys_cmd_network_get_dns(const syscall_args_t *args) { ipv4_address_t *ip = (ipv4_address_t *)args->arg2; if (!ip) return -1; return network_get_dns_ip(ip); } static uint64_t sys_cmd_icmp_ping(const syscall_args_t *args) { ipv4_address_t *dest_ip = (ipv4_address_t *)args->arg2; if (!dest_ip) return -1; extern int network_icmp_single_ping(ipv4_address_t *dest); return (uint64_t)network_icmp_single_ping(dest_ip); } static uint64_t sys_cmd_network_is_init(const syscall_args_t *args) { (void)args; return network_is_initialized() ? 1 : 0; } static uint64_t sys_cmd_get_shell_config(const syscall_args_t *args) { const char *key = (const char *)args->arg2; if (!key) return -1; return cmd_get_config_value(key); } static uint64_t sys_cmd_set_text_color(const syscall_args_t *args) { process_t *proc = process_get_current(); uint32_t color = (uint32_t)args->arg2; if (proc->is_terminal_proc && proc->tty_id >= 0) { char seq[32]; int pos = 0; int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; seq[pos++] = 0x1B; seq[pos++] = '['; seq[pos++] = '3'; seq[pos++] = '8'; seq[pos++] = ';'; seq[pos++] = '2'; seq[pos++] = ';'; char num[8]; itoa(r, num); for (int i = 0; num[i] && pos < (int)sizeof(seq) - 1; i++) seq[pos++] = num[i]; seq[pos++] = ';'; itoa(g, num); for (int i = 0; num[i] && pos < (int)sizeof(seq) - 1; i++) seq[pos++] = num[i]; seq[pos++] = ';'; itoa(b, num); for (int i = 0; num[i] && pos < (int)sizeof(seq) - 1; i++) seq[pos++] = num[i]; seq[pos++] = 'm'; tty_write_output(proc->tty_id, seq, (size_t)pos); return 0; } cmd_set_current_color(color); return 0; } static uint64_t sys_cmd_network_has_ip(const syscall_args_t *args) { (void)args; return network_has_ip() ? 1 : 0; } static uint64_t sys_cmd_set_wallpaper_path(const syscall_args_t *args) { const char *user_path = (const char *)args->arg2; if (!user_path) return -1; // Copy path safely to kernel buffer char kernel_path[256]; int i = 0; while (i < 255 && user_path[i]) { kernel_path[i] = user_path[i]; i++; } kernel_path[i] = 0; extern void wallpaper_request_set_from_file(const char *path); wallpaper_request_set_from_file(kernel_path); return 0; } static uint64_t sys_cmd_rtc_set(const syscall_args_t *args) { int *dt = (int *)args->arg2; if (!dt) return -1; extern void rtc_set_datetime(int y, int m, int d, int h, int min, int s); rtc_set_datetime(dt[0], dt[1], dt[2], dt[3], dt[4], dt[5]); return 0; } static uint64_t sys_cmd_tcp_connect(const syscall_args_t *args) { ipv4_address_t *ip = (ipv4_address_t *)args->arg2; uint16_t port = (uint16_t)args->arg3; extern int network_tcp_connect(const ipv4_address_t *ip, uint16_t port); return (uint64_t)network_tcp_connect(ip, port); } static uint64_t sys_cmd_tcp_send(const syscall_args_t *args) { const void *data = (const void *)args->arg2; size_t len = (size_t)args->arg3; extern int network_tcp_send(const void *data, size_t len); return (uint64_t)network_tcp_send(data, len); } static uint64_t sys_cmd_tcp_recv(const syscall_args_t *args) { void *buf = (void *)args->arg2; size_t max_len = (size_t)args->arg3; extern int network_tcp_recv(void *buf, size_t max_len); return (uint64_t)network_tcp_recv(buf, max_len); } static uint64_t sys_cmd_tcp_close(const syscall_args_t *args) { (void)args; extern int network_tcp_close(void); return (uint64_t)network_tcp_close(); } static uint64_t sys_cmd_dns_lookup(const syscall_args_t *args) { const char *user_name = (const char *)args->arg2; ipv4_address_t *out_ip = (ipv4_address_t *)args->arg3; char name_buf[256]; int i = 0; while (i < 255 && user_name[i]) { name_buf[i] = user_name[i]; i++; } name_buf[i] = 0; extern int network_dns_lookup(const char *name, ipv4_address_t *out_ip); return (uint64_t)network_dns_lookup(name_buf, out_ip); } static uint64_t sys_cmd_set_dns(const syscall_args_t *args) { ipv4_address_t *ip = (ipv4_address_t *)args->arg2; extern int network_set_dns_server(const ipv4_address_t *ip); return (uint64_t)network_set_dns_server(ip); } static uint64_t sys_cmd_net_unlock(const syscall_args_t *args) { (void)args; extern void network_force_unlock(void); network_force_unlock(); return 0; } static uint64_t sys_cmd_set_font(const syscall_args_t *args) { const char *user_path = (const char *)args->arg2; if (!user_path) return -1; // Copy font path from userland char path[128]; int i; for (i = 0; i < 127 && user_path[i]; i++) { path[i] = user_path[i]; } path[i] = 0; graphics_set_font(path); return 0; } static uint64_t sys_cmd_set_raw_mode(const syscall_args_t *args) { extern void cmd_set_raw_mode(bool enabled); cmd_set_raw_mode((bool)args->arg2); return 0; } static uint64_t sys_cmd_tcp_recv_nb(const syscall_args_t *args) { void *buf = (void *)args->arg2; size_t max_len = (size_t)args->arg3; extern int network_tcp_recv_nb(void *buf, size_t max_len); return (uint64_t)network_tcp_recv_nb(buf, max_len); } static uint64_t sys_cmd_set_resolution(const syscall_args_t *args) { uint16_t req_w = (uint16_t)args->arg2; uint16_t req_h = (uint16_t)args->arg3; uint16_t req_bpp = (uint16_t)args->arg4; int req_color_mode = (int)args->arg5; extern bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_framebuffer); extern void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode); extern void wm_refresh(void); extern void vga_set_palette_grayscale(void); extern void vga_set_palette_standard(void); void *new_fb = NULL; if (vga_set_mode(req_w, req_h, req_bpp, &new_fb)) { if (req_color_mode == 1 || req_color_mode == 2) { vga_set_palette_grayscale(); } else if (req_bpp <= 8) { vga_set_palette_standard(); } graphics_update_resolution(req_w, req_h, req_bpp, new_fb, req_color_mode); wm_refresh(); return 0; } return -1; } static uint64_t sys_cmd_network_get_nic_name(const syscall_args_t *args) { char *user_buf = (char *)args->arg2; if (!user_buf) return -1; char name_buf[64]; extern int network_get_nic_name(char *name_out); if (network_get_nic_name(name_buf) == 0) { extern void mem_memcpy(void *dest, const void *src, size_t len); size_t len = 0; while (name_buf[len] && len < 63) len++; name_buf[len] = 0; mem_memcpy(user_buf, name_buf, len + 1); return 0; } return -1; } static uint64_t sys_cmd_parallel_run(const syscall_args_t *args) { process_t *proc = process_get_current(); void (*user_fn)(void*) = (void (*)(void*))args->arg2; void **user_args = (void **)args->arg3; int count = (int)args->arg4; if (count <= 0) return 0; if (count > 64) count = 64; volatile int completion_counter = count; uint64_t current_pml4 = proc->pml4_phys; smp_user_task_t tasks[64]; for (int i = 0; i < count; i++) { tasks[i].fn = user_fn; tasks[i].arg = user_args[i]; tasks[i].pml4_phys = current_pml4; tasks[i].completion_counter = &completion_counter; extern void work_queue_submit(void (*fn)(void*), void *arg); work_queue_submit(smp_user_wrapper, &tasks[i]); } extern bool work_queue_drain_one(void); while (completion_counter > 0) { if (!work_queue_drain_one()) { asm volatile("pause"); } } return 0; } static uint64_t sys_cmd_tty_create(const syscall_args_t *args) { (void)args; return tty_create(); } static uint64_t sys_cmd_tty_read_out(const syscall_args_t *args) { int tty_id = (int)args->arg2; char *buf = (char *)args->arg3; size_t len = (size_t)args->arg4; if (!buf || len == 0) return 0; return tty_read_output(tty_id, buf, len); } static uint64_t sys_cmd_tty_write_in(const syscall_args_t *args) { int tty_id = (int)args->arg2; const char *buf = (const char *)args->arg3; size_t len = (size_t)args->arg4; if (!buf || len == 0) return 0; return tty_write_input(tty_id, buf, len); } static uint64_t sys_cmd_tty_read_in(const syscall_args_t *args) { process_t *proc = process_get_current(); char *buf = (char *)args->arg2; size_t len = (size_t)args->arg3; if (!buf || len == 0) return 0; if (proc->tty_id < 0) return 0; return tty_read_input(proc->tty_id, buf, len); } static uint64_t sys_cmd_spawn_process(const syscall_args_t *args) { process_t *proc = process_get_current(); const char *user_path = (const char *)args->arg2; const char *user_args = (const char *)args->arg3; uint64_t flags = args->arg4; int tty_id = (int)args->arg5; if (!user_path) return -1; char path_buf[256]; int pi = 0; while (pi < 255 && user_path[pi]) { path_buf[pi] = user_path[pi]; pi++; } path_buf[pi] = 0; char args_buf[512]; const char *args_ptr = NULL; if (user_args) { int ai = 0; while (ai < 511 && user_args[ai]) { args_buf[ai] = user_args[ai]; ai++; } args_buf[ai] = 0; args_ptr = args_buf; } bool terminal_proc = (flags & SPAWN_FLAG_TERMINAL) != 0; int effective_tty = -1; if (flags & SPAWN_FLAG_TTY_ID) effective_tty = tty_id; else if (flags & SPAWN_FLAG_INHERIT_TTY) effective_tty = proc ? proc->tty_id : -1; process_t *child = process_create_elf(path_buf, args_ptr, terminal_proc, effective_tty); if (!child) return -1; return (uint64_t)child->pid; } typedef struct { uint64_t sa_handler; uint64_t sa_mask; int sa_flags; } k_sigaction_t; #define SA_RESETHAND 0x80000000 #define SIGKILL_NUM 9 static uint64_t sys_cmd_exec_process(const syscall_args_t *args) { const char *user_path = (const char *)args->arg2; const char *user_args = (const char *)args->arg3; if (!user_path) return -1; char path_buf[256]; int pi = 0; while (pi < 255 && user_path[pi]) { path_buf[pi] = user_path[pi]; pi++; } path_buf[pi] = 0; char args_buf[512]; const char *args_ptr = NULL; if (user_args) { int ai = 0; while (ai < 511 && user_args[ai]) { args_buf[ai] = user_args[ai]; ai++; } args_buf[ai] = 0; args_ptr = args_buf; } return process_exec_replace_current(args->regs, path_buf, args_ptr); } static uint64_t sys_cmd_waitpid(const syscall_args_t *args) { process_t *proc = process_get_current(); int pid = (int)args->arg2; int *status = (int *)args->arg3; int options = (int)args->arg4; if (!proc) return -1; int st = 0; int res = process_waitpid(proc->pid, pid, options, &st); if (res == -2) { if (options & 1) return 0; // WNOHANG return (uint64_t)-2; } if (res < 0) return (uint64_t)-1; if (status) *status = st; return (uint64_t)res; } static uint64_t sys_cmd_kill_signal(const syscall_args_t *args) { int pid = (int)args->arg2; int sig = (int)args->arg3; process_t *target; if (pid == -1) { target = process_get_current(); } else { target = process_get_by_pid((uint32_t)pid); } if (!target) return -1; if (sig == 0) return 0; if (sig <= 0 || sig >= MAX_SIGNALS) return -1; if (sig == 9) { process_terminate_with_status(target, 128 + sig); return 0; } target->signal_pending |= (1ULL << (uint32_t)sig); return 0; } static uint64_t sys_cmd_sigaction(const syscall_args_t *args) { process_t *proc = process_get_current(); int sig = (int)args->arg2; const k_sigaction_t *act = (const k_sigaction_t *)args->arg3; k_sigaction_t *oldact = (k_sigaction_t *)args->arg4; if (!proc || sig <= 0 || sig >= MAX_SIGNALS) return -1; if (oldact) { oldact->sa_handler = proc->signal_handlers[sig]; oldact->sa_mask = proc->signal_action_mask[sig]; oldact->sa_flags = proc->signal_action_flags[sig]; } if (act) { if (sig == SIGKILL_NUM && act->sa_handler != 0) { return -1; } proc->signal_handlers[sig] = act->sa_handler; proc->signal_action_mask[sig] = act->sa_mask; proc->signal_action_flags[sig] = act->sa_flags; } return 0; } static uint64_t sys_cmd_sigprocmask(const syscall_args_t *args) { process_t *proc = process_get_current(); int how = (int)args->arg2; const uint64_t *set = (const uint64_t *)args->arg3; uint64_t *oldset = (uint64_t *)args->arg4; if (!proc) return -1; if (oldset) { *oldset = proc->signal_mask; } if (!set) return 0; if (how == 0) { proc->signal_mask |= *set; } else if (how == 1) { proc->signal_mask &= ~(*set); } else if (how == 2) { proc->signal_mask = *set; } else { return -1; } proc->signal_mask &= ~(1ULL << SIGKILL_NUM); return 0; } static uint64_t sys_cmd_sigpending(const syscall_args_t *args) { process_t *proc = process_get_current(); uint64_t *set = (uint64_t *)args->arg2; if (!proc || !set) return -1; *set = proc->signal_pending; return 0; } static uint64_t sys_cmd_tty_set_fg(const syscall_args_t *args) { int tty_id = (int)args->arg2; int pid = (int)args->arg3; return tty_set_foreground(tty_id, pid); } static uint64_t sys_cmd_tty_get_fg(const syscall_args_t *args) { int tty_id = (int)args->arg2; return tty_get_foreground(tty_id); } static uint64_t sys_cmd_tty_kill_fg(const syscall_args_t *args) { int tty_id = (int)args->arg2; int pid = tty_get_foreground(tty_id); if (pid <= 0) return 0; process_t *target = process_get_by_pid((uint32_t)pid); if (target) process_terminate(target); tty_set_foreground(tty_id, 0); return 0; } static uint64_t sys_cmd_tty_kill_all(const syscall_args_t *args) { int tty_id = (int)args->arg2; process_kill_by_tty(tty_id); tty_set_foreground(tty_id, 0); return 0; } static uint64_t sys_cmd_tty_destroy(const syscall_args_t *args) { int tty_id = (int)args->arg2; return tty_destroy(tty_id); } static uint64_t sys_cmd_get_elf_metadata(const syscall_args_t *args) { const char *path = (const char *)args->arg2; boredos_app_metadata_t *out = (boredos_app_metadata_t *)args->arg3; if (!path || !out) return 0; return app_metadata_read(path, out) ? 1 : 0; } static uint64_t sys_cmd_get_elf_primary_image(const syscall_args_t *args) { const char *path = (const char *)args->arg2; char *out_path = (char *)args->arg3; size_t out_size = (size_t)args->arg4; if (!path || !out_path || !out_size) return 0; return app_metadata_get_primary_image(path, out_path, out_size) ? 1 : 0; } static uint64_t sys_cmd_set_keyboard_layout(const syscall_args_t *args) { keymap_set_current((keymap_id_t)args->arg2); return 0; } static uint64_t sys_cmd_get_keyboard_layout(const syscall_args_t *args) { (void)args; return (uint64_t)keymap_get_current(); } typedef struct { char devname[16]; char label[32]; uint32_t type; uint32_t total_sectors; bool is_partition; bool is_fat32; bool is_esp; uint32_t lba_offset; } k_disk_info_t; typedef struct { uint32_t lba_start; uint32_t sector_count; uint8_t part_type; uint8_t flags; char label[36]; } k_partition_spec_t; static void disk_k_strcpy(char *dst, const char *src, int max) { int i = 0; while (i < max - 1 && src[i]) { dst[i] = src[i]; i++; } dst[i] = 0; } static int disk_k_strcmp(const char *a, const char *b) { while (*a && *a == *b) { a++; b++; } return (unsigned char)*a - (unsigned char)*b; } static uint64_t sys_cmd_disk_get_count(const syscall_args_t *args) { (void)args; return (uint64_t)disk_get_count(); } static uint64_t sys_cmd_disk_get_info(const syscall_args_t *args) { int index = (int)args->arg2; k_disk_info_t *out = (k_disk_info_t *)args->arg3; if (!out) return (uint64_t)-1; Disk *d = disk_get_by_index(index); if (!d) return (uint64_t)-1; disk_k_strcpy(out->devname, d->devname, 16); disk_k_strcpy(out->label, d->label, 32); out->type = (uint32_t)d->type; out->total_sectors = d->total_sectors; out->is_partition = d->is_partition; out->is_fat32 = d->is_fat32; out->is_esp = d->is_esp; out->lba_offset = d->partition_lba_offset; return 0; } static uint64_t sys_cmd_disk_write_gpt(const syscall_args_t *args) { const char *devname = (const char *)args->arg2; k_partition_spec_t *parts = (k_partition_spec_t *)args->arg3; int count = (int)args->arg4; if (!devname || !parts) return (uint64_t)-1; Disk *d = disk_get_by_name(devname); if (!d) return (uint64_t)-1; return (uint64_t)disk_write_gpt(d, (disk_partition_spec_t *)parts, count); } static uint64_t sys_cmd_disk_write_mbr(const syscall_args_t *args) { const char *devname = (const char *)args->arg2; k_partition_spec_t *parts = (k_partition_spec_t *)args->arg3; int count = (int)args->arg4; if (!devname || !parts) return (uint64_t)-1; Disk *d = disk_get_by_name(devname); if (!d) return (uint64_t)-1; return (uint64_t)disk_write_mbr(d, (disk_partition_spec_t *)parts, count); } static uint64_t sys_cmd_disk_mkfs_fat32(const syscall_args_t *args) { extern int mkfs_fat32_format(Disk *disk, uint32_t sector_count, const char *label); const char *devname = (const char *)args->arg2; const char *label = (const char *)args->arg3; if (!devname) return (uint64_t)-1; Disk *d = disk_get_by_name(devname); if (!d) return (uint64_t)-1; int ret = mkfs_fat32_format(d, d->total_sectors, label); if (ret == 0) d->is_fat32 = true; return (uint64_t)ret; } static uint64_t sys_cmd_disk_mount(const syscall_args_t *args) { const char *devname = (const char *)args->arg2; const char *mountpoint = (const char *)args->arg3; if (!devname || !mountpoint) return (uint64_t)-1; Disk *d = disk_get_by_name(devname); if (!d || !d->is_fat32) return (uint64_t)-1; void *vol = fat32_mount_volume(d); if (!vol) return (uint64_t)-1; if (!vfs_mount(mountpoint, devname, "fat32", fat32_get_realfs_ops(), vol)) return (uint64_t)-1; wm_notify_fs_change(); return 0; } static uint64_t sys_cmd_disk_umount(const syscall_args_t *args) { const char *mountpoint = (const char *)args->arg2; if (!mountpoint) return (uint64_t)-1; return vfs_umount(mountpoint) ? 0 : (uint64_t)-1; } static uint64_t sys_cmd_disk_rescan(const syscall_args_t *args) { const char *devname = (const char *)args->arg2; if (!devname) return (uint64_t)-1; Disk *d = disk_get_by_name(devname); if (!d) return (uint64_t)-1; return (uint64_t)disk_rescan(d); } static uint64_t sys_cmd_disk_sync(const syscall_args_t *args) { const char *mountpoint = (const char *)args->arg2; if (!mountpoint) return (uint64_t)-1; int mc = vfs_get_mount_count(); for (int i = 0; i < mc; i++) { vfs_mount_t *m = vfs_get_mount(i); if (m && m->active && disk_k_strcmp(m->path, mountpoint) == 0) { Disk *d = disk_get_by_name(m->device); if (d) return (uint64_t)disk_sync(d); } } return (uint64_t)-1; } static uint64_t sys_cmd_disk_replace_kernel(const syscall_args_t *args) { extern void serial_write(const char *str); const char *src_path = (const char *)args->arg2; const char *esp_mountpoint = (const char *)args->arg3; if (!src_path || !esp_mountpoint) return (uint64_t)-1; char dest_path[256]; int mi = 0; while (mi < 255 && esp_mountpoint[mi]) { dest_path[mi] = esp_mountpoint[mi]; mi++; } const char *suffix = "/boredos.elf"; for (int i = 0; suffix[i] && mi < 255; i++) dest_path[mi++] = suffix[i]; dest_path[mi] = 0; if (disk_k_strcmp(src_path, dest_path) == 0) { serial_write("[KUP] Error: source and destination are the same file\n"); return (uint64_t)-1; } vfs_file_t *src = vfs_open(src_path, "r"); if (!src) { serial_write("[KUP] Error: source not found\n"); return (uint64_t)-1; } uint32_t src_size = vfs_file_size(src); if (src_size > 100 * 1024 * 1024) { serial_write("[KUP] Error: source > 100 MB\n"); vfs_close(src); return (uint64_t)-1; } uint8_t magic[4]; vfs_read(src, magic, 4); if (magic[0] != 0x7F || magic[1] != 'E' || magic[2] != 'L' || magic[3] != 'F') { serial_write("[KUP] Error: not an ELF file\n"); vfs_close(src); return (uint64_t)-1; } vfs_seek(src, 0, 0); char bak_path[256]; mi = 0; while (mi < 255 && esp_mountpoint[mi]) { bak_path[mi] = esp_mountpoint[mi]; mi++; } const char *bak_suffix = "/boredos.elf.bak"; for (int i = 0; bak_suffix[i] && mi < 255; i++) bak_path[mi++] = bak_suffix[i]; bak_path[mi] = 0; vfs_file_t *existing = vfs_open(dest_path, "r"); if (existing) { vfs_file_t *bakf = vfs_open(bak_path, "w"); if (bakf) { uint8_t *cbuf = (uint8_t *)kmalloc(4096); if (cbuf) { int n; while ((n = vfs_read(existing, cbuf, 4096)) > 0) vfs_write(bakf, cbuf, n); kfree(cbuf); } vfs_close(bakf); } else { serial_write("[KUP] Warning: could not create backup\n"); } vfs_close(existing); } vfs_file_t *dst = vfs_open(dest_path, "w"); if (!dst) { serial_write("[KUP] Error: could not open destination for write\n"); vfs_close(src); return (uint64_t)-1; } uint8_t *buf = (uint8_t *)kmalloc(4096); if (!buf) { vfs_close(src); vfs_close(dst); return (uint64_t)-1; } uint32_t bytes_written = 0; int n; while ((n = vfs_read(src, buf, 4096)) > 0) { int written = vfs_write(dst, buf, n); if (written != n) { serial_write("[KUP] Error: write failed mid-copy\n"); kfree(buf); vfs_close(src); vfs_close(dst); return (uint64_t)-1; } bytes_written += (uint32_t)written; } kfree(buf); vfs_close(src); vfs_close(dst); if (bytes_written != src_size) { serial_write("[KUP] Error: incomplete write (size mismatch)\n"); return (uint64_t)-1; } serial_write("[KUP] Kernel replaced ("); { char numstr[16]; int ni = 15; numstr[ni] = 0; uint32_t v = bytes_written; if (v == 0) { numstr[--ni] = '0'; } else { while (v > 0) { numstr[--ni] = '0' + (v % 10); v /= 10; } } serial_write(numstr + ni); } serial_write(" bytes). Backup at boredos.elf.bak. Reboot required.\n"); return 0; } #define SYS_CMD_TABLE_SIZE 110 static const syscall_handler_fn sys_cmd_table[SYS_CMD_TABLE_SIZE] = { [SYSTEM_CMD_SET_BG_COLOR] = sys_cmd_set_bg_color, [SYSTEM_CMD_SET_BG_PATTERN] = sys_cmd_set_bg_pattern, [SYSTEM_CMD_SET_WALLPAPER] = sys_cmd_set_wallpaper, [SYSTEM_CMD_SET_DESKTOP_PROP] = sys_cmd_set_desktop_prop, [SYSTEM_CMD_SET_MOUSE_SPEED] = sys_cmd_set_mouse_speed, [SYSTEM_CMD_NETWORK_INIT] = sys_cmd_network_init, [SYSTEM_CMD_GET_DESKTOP_PROP] = sys_cmd_get_desktop_prop, [SYSTEM_CMD_GET_MOUSE_SPEED] = sys_cmd_get_mouse_speed, [SYSTEM_CMD_GET_WALLPAPER_THUMB] = sys_cmd_get_wallpaper_thumb, [SYSTEM_CMD_CLEAR_SCREEN] = sys_cmd_clear_screen, [SYSTEM_CMD_RTC_GET] = sys_cmd_rtc_get, [SYSTEM_CMD_REBOOT] = sys_cmd_reboot, [SYSTEM_CMD_SHUTDOWN] = sys_cmd_shutdown, [SYSTEM_CMD_BEEP] = sys_cmd_beep, [SYSTEM_CMD_GET_MEM_INFO] = sys_cmd_get_mem_info, [SYSTEM_CMD_GET_TICKS] = sys_cmd_get_ticks, [SYSTEM_CMD_PCI_LIST] = sys_cmd_pci_list, [SYSTEM_CMD_NETWORK_DHCP] = sys_cmd_network_dhcp, [SYSTEM_CMD_NETWORK_GET_MAC] = sys_cmd_network_get_mac, [SYSTEM_CMD_NETWORK_GET_IP] = sys_cmd_network_get_ip, [SYSTEM_CMD_NETWORK_SET_IP] = sys_cmd_network_set_ip, [SYSTEM_CMD_UDP_SEND] = sys_cmd_udp_send, [SYSTEM_CMD_NETWORK_GET_STATS] = sys_cmd_network_get_stats, [SYSTEM_CMD_NETWORK_GET_GATEWAY] = sys_cmd_network_get_gateway, [SYSTEM_CMD_NETWORK_GET_DNS] = sys_cmd_network_get_dns, [SYSTEM_CMD_ICMP_PING] = sys_cmd_icmp_ping, [SYSTEM_CMD_NETWORK_IS_INIT] = sys_cmd_network_is_init, [SYSTEM_CMD_GET_SHELL_CONFIG] = sys_cmd_get_shell_config, [SYSTEM_CMD_SET_TEXT_COLOR] = sys_cmd_set_text_color, [SYSTEM_CMD_NETWORK_HAS_IP] = sys_cmd_network_has_ip, [SYSTEM_CMD_SET_WALLPAPER_PATH] = sys_cmd_set_wallpaper_path, [SYSTEM_CMD_RTC_SET] = sys_cmd_rtc_set, [SYSTEM_CMD_TCP_CONNECT] = sys_cmd_tcp_connect, [SYSTEM_CMD_TCP_SEND] = sys_cmd_tcp_send, [SYSTEM_CMD_TCP_RECV] = sys_cmd_tcp_recv, [SYSTEM_CMD_TCP_CLOSE] = sys_cmd_tcp_close, [SYSTEM_CMD_DNS_LOOKUP] = sys_cmd_dns_lookup, [SYSTEM_CMD_SET_DNS] = sys_cmd_set_dns, [SYSTEM_CMD_NET_UNLOCK] = sys_cmd_net_unlock, [SYSTEM_CMD_SET_FONT] = sys_cmd_set_font, [SYSTEM_CMD_SET_RAW_MODE] = sys_cmd_set_raw_mode, [SYSTEM_CMD_TCP_RECV_NB] = sys_cmd_tcp_recv_nb, [SYSTEM_CMD_SET_RESOLUTION] = sys_cmd_set_resolution, [SYSTEM_CMD_NETWORK_GET_NIC_NAME] = sys_cmd_network_get_nic_name, [SYSTEM_CMD_PARALLEL_RUN] = sys_cmd_parallel_run, [SYSTEM_CMD_SET_KEYBOARD_LAYOUT] = sys_cmd_set_keyboard_layout, [SYSTEM_CMD_GET_KEYBOARD_LAYOUT] = sys_cmd_get_keyboard_layout, [SYSTEM_CMD_SET_MOUSE_CURSOR_SCALE] = sys_cmd_set_mouse_cursor_scale, [SYSTEM_CMD_GET_MOUSE_CURSOR_SCALE] = sys_cmd_get_mouse_cursor_scale, [SYSTEM_CMD_TTY_CREATE] = sys_cmd_tty_create, [SYSTEM_CMD_TTY_READ_OUT] = sys_cmd_tty_read_out, [SYSTEM_CMD_TTY_WRITE_IN] = sys_cmd_tty_write_in, [SYSTEM_CMD_TTY_READ_IN] = sys_cmd_tty_read_in, [SYSTEM_CMD_SPAWN] = sys_cmd_spawn_process, [SYSTEM_CMD_TTY_SET_FG] = sys_cmd_tty_set_fg, [SYSTEM_CMD_TTY_GET_FG] = sys_cmd_tty_get_fg, [SYSTEM_CMD_TTY_KILL_FG] = sys_cmd_tty_kill_fg, [SYSTEM_CMD_TTY_KILL_ALL] = sys_cmd_tty_kill_all, [SYSTEM_CMD_TTY_DESTROY] = sys_cmd_tty_destroy, [SYSTEM_CMD_EXEC] = sys_cmd_exec_process, [SYSTEM_CMD_WAITPID] = sys_cmd_waitpid, [SYSTEM_CMD_KILL_SIGNAL] = sys_cmd_kill_signal, [SYSTEM_CMD_SIGACTION] = sys_cmd_sigaction, [SYSTEM_CMD_SIGPROCMASK] = sys_cmd_sigprocmask, [SYSTEM_CMD_SIGPENDING] = sys_cmd_sigpending, [SYSTEM_CMD_GET_ELF_METADATA] = sys_cmd_get_elf_metadata, [SYSTEM_CMD_GET_ELF_PRIMARY_IMAGE] = sys_cmd_get_elf_primary_image, [SYSTEM_CMD_DISK_GET_COUNT] = sys_cmd_disk_get_count, [SYSTEM_CMD_DISK_GET_INFO] = sys_cmd_disk_get_info, [SYSTEM_CMD_DISK_WRITE_GPT] = sys_cmd_disk_write_gpt, [SYSTEM_CMD_DISK_WRITE_MBR] = sys_cmd_disk_write_mbr, [SYSTEM_CMD_DISK_MKFS_FAT32] = sys_cmd_disk_mkfs_fat32, [SYSTEM_CMD_DISK_MOUNT] = sys_cmd_disk_mount, [SYSTEM_CMD_DISK_UMOUNT] = sys_cmd_disk_umount, [SYSTEM_CMD_DISK_RESCAN] = sys_cmd_disk_rescan, [SYSTEM_CMD_DISK_REPLACE_KERNEL] = sys_cmd_disk_replace_kernel, [SYSTEM_CMD_DISK_SYNC] = sys_cmd_disk_sync, }; static uint64_t handle_sys_write(const syscall_args_t *args) { extern void cmd_write_len(const char *str, size_t len); process_t *proc = process_get_current(); const char *buf = (const char*)args->arg2; size_t len = (size_t)args->arg3; if (!proc || !proc->is_user) { cmd_write_len(buf, len); return len; } if (proc->is_terminal_proc) { if (proc->tty_id >= 0) { tty_write_output(proc->tty_id, buf, len); return len; } cmd_write_len(buf, len); return len; } return len; } static uint64_t handle_sys_gui(const syscall_args_t *args) { int cmd = (int)args->arg1; if (cmd >= 0 && cmd < GUI_CMD_TABLE_SIZE && gui_cmd_table[cmd]) { return gui_cmd_table[cmd](args); } return 0; } static uint64_t handle_sys_fs(const syscall_args_t *args) { int cmd = (int)args->arg1; if (cmd >= 0 && cmd < FS_CMD_TABLE_SIZE && fs_cmd_table[cmd]) { return fs_cmd_table[cmd](args); } return 0; } static uint64_t handle_sys_system(const syscall_args_t *args) { int cmd = (int)args->arg1; if (cmd >= 0 && cmd < SYS_CMD_TABLE_SIZE && sys_cmd_table[cmd]) { return sys_cmd_table[cmd](args); } return -1; } static uint64_t handle_debug_serial_write(const syscall_args_t *args) { extern void serial_write(const char *str); serial_write((const char *)args->arg2); return 0; } static uint64_t handle_sys_sbrk(const syscall_args_t *args) { int incr = (int)args->arg1; process_t *proc = process_get_current(); if (!proc || !proc->is_user) return (uint64_t)-1; uint64_t old_end = proc->heap_end; if (incr == 0) return old_end; uint64_t new_end = old_end + incr; if (incr > 0) { uint64_t start_page = (old_end + 0xFFF) & ~0xFFF; uint64_t end_page = (new_end + 0xFFF) & ~0xFFF; if (end_page > start_page) { uint64_t total_size = end_page - start_page; void *phys_block = kmalloc_aligned(total_size, 4096); if (!phys_block) return (uint64_t)-1; // Out of memory extern void mem_memset(void *dest, int val, size_t len); mem_memset(phys_block, 0, total_size); uint64_t phys_addr = (uint64_t)phys_block; for (uint64_t page = start_page; page < end_page; page += 4096) { paging_map_page(proc->pml4_phys, page, v2p(phys_addr), 0x07); // PT_PRESENT | PT_RW | PT_USER phys_addr += 4096; } proc->used_memory += (end_page - start_page); } } proc->heap_end = new_end; return old_end; } static uint64_t handle_sys_kill(const syscall_args_t *args) { (void)args; return 0; } #define SYSCALL_TABLE_SIZE 11 static const syscall_handler_fn syscall_table[SYSCALL_TABLE_SIZE] = { [SYS_WRITE] = handle_sys_write, [SYS_GUI] = handle_sys_gui, [SYS_FS] = handle_sys_fs, [5] = handle_sys_system, [8] = handle_debug_serial_write, [9] = handle_sys_sbrk, [10] = handle_sys_kill, }; static uint64_t syscall_handler_inner(registers_t *regs) { uint64_t syscall_num = regs->rax; syscall_args_t args = { .regs = regs, .arg1 = regs->rdi, .arg2 = regs->rsi, .arg3 = regs->rdx, .arg4 = regs->r10, .arg5 = regs->r8, }; if (syscall_num < SYSCALL_TABLE_SIZE && syscall_table[syscall_num]) { return syscall_table[syscall_num](&args); } return 0; } static uint64_t syscall_maybe_deliver_signal(registers_t *regs) { process_t *proc = process_get_current(); if (!proc || !proc->is_user) return (uint64_t)regs; uint64_t pending = proc->signal_pending & ~proc->signal_mask; if (!pending) return (uint64_t)regs; int sig = -1; for (int i = 1; i < MAX_SIGNALS; i++) { if (pending & (1ULL << (uint32_t)i)) { sig = i; break; } } if (sig < 0) return (uint64_t)regs; proc->signal_pending &= ~(1ULL << (uint32_t)sig); uint64_t handler = proc->signal_handlers[sig]; int flags = proc->signal_action_flags[sig]; if (handler == 1) { return (uint64_t)regs; } if (handler == 0 || sig == 9) { process_terminate_with_status(proc, 128 + sig); return process_schedule((uint64_t)regs); } if (flags & SA_RESETHAND) { proc->signal_handlers[sig] = 0; proc->signal_action_mask[sig] = 0; proc->signal_action_flags[sig] = 0; } uint64_t new_rsp = regs->rsp - sizeof(uint64_t); *((uint64_t *)new_rsp) = regs->rip; regs->rsp = new_rsp; regs->rip = handler; regs->rdi = (uint64_t)sig; return (uint64_t)regs; } uint64_t syscall_handler_c(registers_t *regs) { uint64_t syscall_num = regs->rax; // Check for context-switching syscalls if (syscall_num == 0 || syscall_num == 60) { // EXIT return process_terminate_current(); } if (syscall_num == 10) { // KILL uint32_t target_pid = (uint32_t)regs->rdi; process_t *current = process_get_current(); if (target_pid == 0) { // Protect kernel process regs->rax = -1; return (uint64_t)regs; } if (target_pid == 0xFFFFFFFF || target_pid == current->pid) { return process_terminate_current(); } else { process_t *target = process_get_by_pid(target_pid); if (target) { process_terminate(target); } regs->rax = 0; return (uint64_t)regs; } } if (syscall_num == SYS_SYSTEM && regs->rdi == SYSTEM_CMD_YIELD) { extern uint64_t process_schedule(uint64_t current_rsp); regs->rax = 0; return process_schedule((uint64_t)regs); } if (syscall_num == SYS_SYSTEM && regs->rdi == SYSTEM_CMD_SLEEP) { uint32_t ms = (uint32_t)regs->rsi; process_t *proc = process_get_current(); extern uint32_t wm_get_ticks(void); uint32_t ticks = ms / 16; if (ticks == 0 && ms > 0) ticks = 1; proc->sleep_until = wm_get_ticks() + ticks; regs->rax = 0; return process_schedule((uint64_t)regs); } // Normal syscalls regs->rax = syscall_handler_inner(regs); if (syscall_num == SYS_SYSTEM && regs->rdi == SYSTEM_CMD_WAITPID && regs->rax == (uint64_t)-2) { regs->rax = 0; return process_schedule((uint64_t)regs); } return syscall_maybe_deliver_signal(regs); }