diff --git a/boredos.iso b/boredos.iso index 2060509..6d256c6 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/build/cmd.o b/build/cmd.o index c013c21..d5a96fb 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index fe21c44..c012aec 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -871,10 +871,12 @@ void cmd_screen_clear() { for(int c=0; c 0) { cmd_putchar('\n'); } @@ -2000,6 +2000,21 @@ void cmd_handle_click(Window *win, int x, int y) { } } +static void cmd_handle_close(Window *win) { + if (!win) return; + + extern process_t* process_get_by_ui_window(void *win); + extern void process_terminate(process_t *proc); + + // Find any process associated with this terminal window and terminate it + process_t *proc = process_get_by_ui_window(win); + if (proc) { + process_terminate(proc); + } + + win->visible = false; +} + void cmd_set_raw_mode(bool enabled) { terminal_raw_mode = enabled; } @@ -2470,6 +2485,7 @@ void cmd_init(void) { win_cmd.handle_key = cmd_key; win_cmd.handle_click = cmd_handle_click; win_cmd.handle_right_click = NULL; + win_cmd.handle_close = cmd_handle_close; win_cmd.handle_resize = cmd_handle_resize; win_cmd.resizable = true; diff --git a/src/kernel/images/.DS_Store b/src/kernel/images/.DS_Store index 808b432..5c63c0d 100644 Binary files a/src/kernel/images/.DS_Store and b/src/kernel/images/.DS_Store differ diff --git a/src/kernel/network.c b/src/kernel/network.c index 59c0284..6a4e501 100644 --- a/src/kernel/network.c +++ b/src/kernel/network.c @@ -272,6 +272,27 @@ int network_tcp_recv(void *buf, size_t max_len) { return (int)copied; } +int network_tcp_recv_nb(void *buf, size_t max_len) { + if (network_processing) return -1; + network_processing = 1; + + if (!tcp_recv_queue) { + network_processing = 0; + return 0; + } + + size_t to_copy = max_len; + if (to_copy > tcp_recv_queue->tot_len) to_copy = tcp_recv_queue->tot_len; + if (to_copy > 0xFFFF) to_copy = 0xFFFF; // pbuf_copy_partial limit + + size_t copied = pbuf_copy_partial(tcp_recv_queue, buf, (u16_t)to_copy, 0); + struct pbuf *remainder = pbuf_free_header(tcp_recv_queue, (u16_t)copied); + if (current_tcp_pcb) tcp_recved(current_tcp_pcb, (u16_t)copied); + tcp_recv_queue = remainder; + network_processing = 0; + return (int)copied; +} + int network_tcp_close(void) { if (network_processing) return 0; network_processing = 1; diff --git a/src/kernel/network.h b/src/kernel/network.h index fa8039d..3e1c15a 100644 --- a/src/kernel/network.h +++ b/src/kernel/network.h @@ -89,6 +89,13 @@ int network_dhcp_acquire(void); int network_get_gateway_ip(ipv4_address_t* ip); int network_get_dns_ip(ipv4_address_t *ip); int network_icmp_single_ping(ipv4_address_t *dest); +int network_tcp_connect(const ipv4_address_t *ip, uint16_t port); +int network_tcp_send(const void *data, size_t len); +int network_tcp_recv(void *buf, size_t max_len); +int network_tcp_recv_nb(void *buf, size_t max_len); +int network_tcp_close(void); +int network_dns_lookup(const char *name, ipv4_address_t *out_ip); +int network_set_dns_server(const ipv4_address_t *ip); void network_cleanup(void); void network_force_unlock(void); diff --git a/src/kernel/process.c b/src/kernel/process.c index e26d019..529e98f 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -329,6 +329,72 @@ uint64_t process_schedule(uint64_t current_rsp) { return current_process->rsp; } +static void process_cleanup_inner(process_t *proc) { + if (!proc || proc->pid == 0xFFFFFFFF) return; + + // 1. Cleanup side effects + extern Window win_cmd; + if (proc->ui_window && (proc->ui_window != &win_cmd)) { + wm_remove_window((Window *)proc->ui_window); + proc->ui_window = NULL; + } + + extern void fat32_close(struct FAT32_FileHandle *fh); + for (int i = 0; i < MAX_PROCESS_FDS; i++) { + if (proc->fds[i]) { + fat32_close(proc->fds[i]); + proc->fds[i] = NULL; + } + } + + extern void cmd_process_finished(void); + cmd_process_finished(); + + extern void network_cleanup_pcb(void *pcb); + // TODO: We need per-process PCB tracking to call this safely + // For now, let's NOT call global network_cleanup +} + +void process_terminate(process_t *to_delete) { + if (!to_delete || to_delete->pid == 0xFFFFFFFF) return; + + uint64_t rflags; + asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + + process_cleanup_inner(to_delete); + + // 2. Find previous process in circular list + process_t *prev = to_delete; + while (prev->next != to_delete) { + prev = prev->next; + } + + if (prev == to_delete) { + // Only one process (should be kernel), cannot terminate. + asm volatile("push %0; popfq" : : "r"(rflags)); + return; + } + + // 3. Remove current from list + prev->next = to_delete->next; + + if (to_delete == current_process) { + current_process = to_delete->next; + // WARNING: If this was called as a regular function and not via a task switch, + // the stack might be in a weird state. But usually we call this via window manager + // or other external triggers. + } + + // Mark slot as free + to_delete->pid = 0xFFFFFFFF; + + if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc); + to_delete->user_stack_alloc = NULL; + to_delete->kernel_stack_alloc = NULL; + + asm volatile("push %0; popfq" : : "r"(rflags)); +} + uint64_t process_terminate_current(void) { uint64_t rflags; asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); @@ -338,26 +404,7 @@ uint64_t process_terminate_current(void) { return 0; } - // 1. Cleanup side effects - extern Window win_cmd; - if (current_process->ui_window && (current_process->ui_window != &win_cmd)) { - wm_remove_window((Window *)current_process->ui_window); - current_process->ui_window = NULL; - } - - extern void fat32_close(struct FAT32_FileHandle *fh); - for (int i = 0; i < MAX_PROCESS_FDS; i++) { - if (current_process->fds[i]) { - fat32_close(current_process->fds[i]); - current_process->fds[i] = NULL; - } - } - - extern void cmd_process_finished(void); - cmd_process_finished(); - - extern void network_cleanup(void); - network_cleanup(); + process_cleanup_inner(current_process); // 2. Find previous process in circular list process_t *prev = current_process; diff --git a/src/kernel/process.h b/src/kernel/process.h index 47c7418..cdd3f29 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -55,6 +55,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str); process_t* process_get_current(void); uint64_t process_schedule(uint64_t current_rsp); uint64_t process_terminate_current(void); +void process_terminate(process_t *proc); void process_push_gui_event(process_t *proc, gui_event_t *ev); process_t* process_get_by_ui_window(void* win); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 4e5a387..d6743c7 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -153,7 +153,14 @@ static void user_window_resize(Window *win, int w, int h) { } -static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { +static uint64_t syscall_handler_inner(registers_t *regs) { + uint64_t syscall_num = regs->rax; + uint64_t arg1 = regs->rdi; + uint64_t arg2 = regs->rsi; + uint64_t arg3 = regs->rdx; + uint64_t arg4 = regs->r10; + uint64_t arg5 = regs->r8; + extern void cmd_write(const char *str); extern void serial_write(const char *str); @@ -561,7 +568,7 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6 } else if (cmd == GUI_CMD_GET_EVENT) { Window *win = (Window *)arg2; gui_event_t *ev_out = (gui_event_t *)arg3; - if (!win || !ev_out) return 0; + 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; @@ -1056,6 +1063,11 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6 extern void cmd_set_raw_mode(bool enabled); cmd_set_raw_mode((bool)arg2); return 0; + } else if (cmd == 42) { // SYSTEM_CMD_TCP_RECV_NB + void *buf = (void *)arg2; + size_t max_len = (size_t)arg3; + extern int network_tcp_recv_nb(void *buf, size_t max_len); + return (uint64_t)network_tcp_recv_nb(buf, max_len); } return -1; } @@ -1071,8 +1083,14 @@ uint64_t syscall_handler_c(registers_t *regs) { return process_terminate_current(); } + if (syscall_num == 5 && regs->rdi == 43) { // SYSTEM_CMD_YIELD + extern uint64_t process_schedule(uint64_t current_rsp); + regs->rax = 0; + return process_schedule((uint64_t)regs); + } + // Normal syscalls - regs->rax = syscall_handler_inner(regs->rax, regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8); + regs->rax = syscall_handler_inner(regs); // Return current RSP to assembly wrapper return (uint64_t)regs; diff --git a/src/kernel/userland/libc/syscall.c b/src/kernel/userland/libc/syscall.c index 2d36e88..6f40b2b 100644 --- a/src/kernel/userland/libc/syscall.c +++ b/src/kernel/userland/libc/syscall.c @@ -207,6 +207,10 @@ int sys_tcp_recv(void *buf, size_t max_len) { return (int)syscall3(SYS_SYSTEM, SYSTEM_CMD_TCP_RECV, (uint64_t)buf, (uint64_t)max_len); } +int sys_tcp_recv_nb(void *buf, size_t max_len) { + return (int)syscall3(SYS_SYSTEM, SYSTEM_CMD_TCP_RECV_NB, (uint64_t)buf, (uint64_t)max_len); +} + int sys_tcp_close(void) { return (int)syscall2(SYS_SYSTEM, SYSTEM_CMD_TCP_CLOSE, 0); } @@ -223,3 +227,7 @@ void sys_network_force_unlock(void) { syscall2(SYS_SYSTEM, SYSTEM_CMD_NET_UNLOCK, 0); } +void sys_yield(void) { + syscall1(SYS_SYSTEM, SYSTEM_CMD_YIELD); +} + diff --git a/src/kernel/userland/libc/syscall.h b/src/kernel/userland/libc/syscall.h index cd7cb75..2341f91 100644 --- a/src/kernel/userland/libc/syscall.h +++ b/src/kernel/userland/libc/syscall.h @@ -69,6 +69,8 @@ #define SYSTEM_CMD_SET_DNS 38 #define SYSTEM_CMD_NET_UNLOCK 39 #define SYSTEM_CMD_SET_RAW_MODE 41 +#define SYSTEM_CMD_TCP_RECV_NB 42 +#define SYSTEM_CMD_YIELD 43 // Internal assembly entry into Ring 0 extern uint64_t syscall0(uint64_t sys_num); @@ -133,10 +135,12 @@ void sys_set_text_color(uint32_t color); int sys_tcp_connect(const net_ipv4_address_t *ip, uint16_t port); int sys_tcp_send(const void *data, size_t len); int sys_tcp_recv(void *buf, size_t max_len); +int sys_tcp_recv_nb(void *buf, size_t max_len); int sys_tcp_close(void); int sys_dns_lookup(const char *name, net_ipv4_address_t *out_ip); int sys_set_dns_server(const net_ipv4_address_t *ip); void sys_network_force_unlock(void); +void sys_yield(void); #endif diff --git a/src/kernel/userland/telnet.c b/src/kernel/userland/telnet.c index 5c096f2..e355e53 100644 --- a/src/kernel/userland/telnet.c +++ b/src/kernel/userland/telnet.c @@ -363,7 +363,7 @@ int main(int argc, char **argv) { } if (!connected) break; - int len = sys_tcp_recv(recv_buf, sizeof(recv_buf) - 1); + int len = sys_tcp_recv_nb(recv_buf, sizeof(recv_buf) - 1); if (len < 0) { printf("\r\n[Connection error]\r\n"); connected = 0; @@ -377,8 +377,7 @@ int main(int argc, char **argv) { connected = 0; break; } - // Brief spin - for (volatile int d = 0; d < 100; d++); + sys_yield(); continue; }