diff --git a/boredos.iso b/boredos.iso index d180931..97fd84d 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/build/idt.o b/build/idt.o index 8c46378..7dee36a 100644 Binary files a/build/idt.o and b/build/idt.o differ diff --git a/build/main.o b/build/main.o index db5e58b..a5addfc 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/memory_manager.o b/build/memory_manager.o index 9546f20..35707d6 100644 Binary files a/build/memory_manager.o and b/build/memory_manager.o differ diff --git a/build/ps2.o b/build/ps2.o index f84b177..8ab922f 100644 Binary files a/build/ps2.o and b/build/ps2.o differ diff --git a/src/kernel/interrupts.asm b/src/kernel/interrupts.asm index ffe1131..ac7af39 100644 --- a/src/kernel/interrupts.asm +++ b/src/kernel/interrupts.asm @@ -29,9 +29,9 @@ isr%2_wrapper: push rbx push rcx push rdx - push rbp - push rdi push rsi + push rdi + push rbp push r8 push r9 push r10 @@ -57,9 +57,9 @@ isr%2_wrapper: pop r10 pop r9 pop r8 - pop rsi - pop rdi pop rbp + pop rdi + pop rsi pop rdx pop rcx pop rbx @@ -134,9 +134,9 @@ exception_common: push rbx push rcx push rdx - push rbp - push rdi push rsi + push rdi + push rbp push r8 push r9 push r10 @@ -163,9 +163,9 @@ exception_common: pop r10 pop r9 pop r8 - pop rsi - pop rdi pop rbp + pop rdi + pop rsi pop rdx pop rcx pop rbx diff --git a/src/kernel/memory_manager.c b/src/kernel/memory_manager.c index 6ade422..26d4a44 100644 --- a/src/kernel/memory_manager.c +++ b/src/kernel/memory_manager.c @@ -60,14 +60,18 @@ static uint32_t get_timestamp(void) { // Sorts the block list by address. This is crucial for efficient merging of free blocks. static void sort_block_list() { + bool swapped; for (int i = 0; i < block_count - 1; i++) { - for (int j = i + 1; j < block_count; j++) { - if ((uintptr_t)block_list[i].address > (uintptr_t)block_list[j].address) { - MemBlock tmp = block_list[i]; - block_list[i] = block_list[j]; - block_list[j] = tmp; + swapped = false; + for (int j = 0; j < block_count - i - 1; j++) { + if ((uintptr_t)block_list[j].address > (uintptr_t)block_list[j + 1].address) { + MemBlock tmp = block_list[j]; + block_list[j] = block_list[j + 1]; + block_list[j + 1] = tmp; + swapped = true; } } + if (!swapped) break; } } @@ -167,34 +171,48 @@ void* kmalloc_aligned(size_t size, size_t alignment) { size_t padding = aligned_addr - block_start; if (block_size >= size + padding) { - void* ptr = (void*)aligned_addr; + int needed_slots = 0; + if (padding > 0) needed_slots++; size_t remaining_size = block_size - (size + padding); - - // The original free block becomes the trailing free part. - block_list[i].address = (void*)(aligned_addr + size); - block_list[i].size = remaining_size; - if (remaining_size == 0) { - for (int j = i; j < block_count - 1; j++) block_list[j] = block_list[j+1]; - block_count--; + if (remaining_size > 0) { + needed_slots++; + } else { + // The current slot will be reused for the allocation. } - // Create a new block for the allocation. - if (block_count >= MAX_ALLOCATIONS) continue; - block_list[block_count].address = ptr; - block_list[block_count].size = size; - block_list[block_count].allocated = true; - block_list[block_count].allocation_id = ++allocation_counter; - block_list[block_count].timestamp = get_timestamp(); - block_count++; + if (block_count + needed_slots > MAX_ALLOCATIONS) { + continue; // Cannot fit metadata for this split + } + + void* ptr = (void*)aligned_addr; + + // Perform the split + if (remaining_size > 0) { + + block_list[block_count].address = ptr; + block_list[block_count].size = size; + block_list[block_count].allocated = true; + block_list[block_count].allocation_id = ++allocation_counter; + block_list[block_count].timestamp = get_timestamp(); + block_count++; + + block_list[i].address = (void*)(aligned_addr + size); + block_list[i].size = remaining_size; + block_list[i].allocated = false; + } else { + block_list[i].address = ptr; + block_list[i].size = size; + block_list[i].allocated = true; + block_list[i].allocation_id = ++allocation_counter; + block_list[i].timestamp = get_timestamp(); + } - // Create a new block for the leading padding if it exists. if (padding > 0) { - if (block_count < MAX_ALLOCATIONS) { - block_list[block_count].address = (void*)block_start; - block_list[block_count].size = padding; - block_list[block_count].allocated = false; - block_count++; - } + block_list[block_count].address = (void*)block_start; + block_list[block_count].size = padding; + block_list[block_count].allocated = false; + block_list[block_count].allocation_id = 0; + block_count++; } sort_block_list(); @@ -237,8 +255,20 @@ void kfree(void *ptr) { total_allocated -= block_list[block_idx].size; block_list[block_idx].allocated = false; + block_list[block_idx].allocation_id = 0; - // Merge with next block if it's free and physically adjacent + // Merge adjacent blocks. We sort first to make adjacency checking trivial. + sort_block_list(); + + // Re-find the block (it might have moved during sort) + for (int i = 0; i < block_count; i++) { + if (block_list[i].address == ptr) { + block_idx = i; + break; + } + } + + // Merge with next block if possible if (block_idx + 1 < block_count && !block_list[block_idx + 1].allocated) { uintptr_t current_end = (uintptr_t)block_list[block_idx].address + block_list[block_idx].size; uintptr_t next_start = (uintptr_t)block_list[block_idx + 1].address; @@ -249,7 +279,7 @@ void kfree(void *ptr) { } } - // Merge with previous block if it's free and physically adjacent + // Merge with previous block if possible if (block_idx > 0 && !block_list[block_idx - 1].allocated) { uintptr_t prev_end = (uintptr_t)block_list[block_idx - 1].address + block_list[block_idx - 1].size; uintptr_t current_start = (uintptr_t)block_list[block_idx].address; @@ -257,8 +287,6 @@ void kfree(void *ptr) { block_list[block_idx - 1].size += block_list[block_idx].size; for (int i = block_idx; i < block_count - 1; i++) block_list[i] = block_list[i + 1]; block_count--; - asm volatile("push %0; popfq" : : "r"(rflags)); - return; } } @@ -298,6 +326,7 @@ void* krealloc(void *ptr, size_t new_size) { MemStats memory_get_stats(void) { MemStats stats; + mem_memset(&stats, 0, sizeof(MemStats)); stats.total_memory = memory_pool_size; stats.used_memory = total_allocated; diff --git a/src/kernel/process.c b/src/kernel/process.c index fa5bbf6..3c0b68c 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -108,9 +108,19 @@ void process_create(void* entry_point, bool is_user) { } process_t* process_create_elf(const char* filepath, const char* args_str) { - if (process_count >= MAX_PROCESSES) return NULL; + process_t *new_proc = NULL; + + // Find an available slot + for (int i = 0; i < MAX_PROCESSES; i++) { + if (processes[i].pid == 0xFFFFFFFF || i >= process_count) { + new_proc = &processes[i]; + if (i >= process_count) process_count = i + 1; + break; + } + } - process_t *new_proc = &processes[process_count]; + if (!new_proc) return NULL; + new_proc->pid = next_pid++; new_proc->is_user = true; @@ -248,8 +258,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) { new_proc->user_stack_alloc = stack; new_proc->rsp = (uint64_t)stack_ptr; - // We only increment process_count after success - process_count++; + // Slot is already counted in process_count if new, or reused. // Add to linked list new_proc->next = current_process->next; @@ -291,13 +300,17 @@ uint64_t process_schedule(uint64_t current_rsp) { } uint64_t process_terminate_current(void) { - if (!current_process) return 0; + uint64_t rflags; + asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + + if (!current_process) { + asm volatile("push %0; popfq" : : "r"(rflags)); + return 0; + } // 1. Cleanup side effects extern Window win_cmd; if (current_process->ui_window && (current_process->ui_window != &win_cmd)) { - extern void serial_write(const char *str); - serial_write("PROC: Terminating proc with window\n"); wm_remove_window((Window *)current_process->ui_window); current_process->ui_window = NULL; } @@ -324,13 +337,14 @@ uint64_t process_terminate_current(void) { if (prev == current_process) { // Only one process (should be kernel), cannot terminate. + asm volatile("push %0; popfq" : : "r"(rflags)); return to_delete->rsp; } prev->next = to_delete->next; current_process = to_delete->next; - // Mark slot as freeish (simple version) + // Mark slot as free to_delete->pid = 0xFFFFFFFF; // 4. Load context for the NEXT process @@ -343,13 +357,17 @@ uint64_t process_terminate_current(void) { paging_switch_directory(current_process->pml4_phys); // 5. Actually free the memory (after switching state to avoid issues) - if (to_delete->kernel_stack_alloc) kfree(to_delete->kernel_stack_alloc); + // We only safely free the user stack. Immediate freeing of the current + // kernel stack is unsafe while we are still running on it. if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc); - // NOTE: In a real system we would also free all physical pages - // used by the user page table. For now we just free the stacks. - - return current_process->rsp; + // Clear pointers to avoid double-free during slot reuse + to_delete->user_stack_alloc = NULL; + to_delete->kernel_stack_alloc = NULL; // Leak the small kernel stack for safety + + uint64_t next_rsp = current_process->rsp; + asm volatile("push %0; popfq" : : "r"(rflags)); + return next_rsp; } void process_push_gui_event(process_t *proc, gui_event_t *ev) { diff --git a/src/kernel/process.h b/src/kernel/process.h index d34b22e..06b9bb3 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -14,7 +14,7 @@ struct FAT32_FileHandle; // Registers saved on the stack by interrupts/exceptions -typedef struct { +typedef struct registers_t { uint64_t r15, r14, r13, r12, r11, r10, r9, r8; uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax; uint64_t int_no, err_code; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index f28f53b..26f90e8 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -131,20 +131,12 @@ static void user_window_key(Window *win, char c) { } -uint64_t syscall_handler_c(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(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { extern void cmd_write(const char *str); extern void serial_write(const char *str); - extern void cmd_process_finished(void); if (syscall_num == 1) { // SYS_WRITE cmd_write((const char*)arg2); - } else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT - uint64_t next_rsp = process_terminate_current(); - extern void context_switch_to(uint64_t rsp); - context_switch_to(next_rsp); - - // This point is never reached - while(1); } else if (syscall_num == 3) { // SYS_GUI int cmd = (int)arg1; process_t *proc = process_get_current(); @@ -501,11 +493,7 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u serial_write((const char *)arg2); return 0; } else if (syscall_num == 10) { // SYS_KILL - // Simplified kill: just terminate current for now - uint64_t next_rsp = process_terminate_current(); - extern void context_switch_to(uint64_t rsp); - context_switch_to(next_rsp); - while(1); + return 0; // Handled in outer } else if (syscall_num == 9) { // SYS_SBRK int incr = (int)arg1; process_t *proc = process_get_current(); @@ -739,3 +727,18 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u return 0; } + +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 || syscall_num == 10) { // EXIT or KILL + return process_terminate_current(); + } + + // Normal syscalls + regs->rax = syscall_handler_inner(regs->rax, regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8); + + // Return current RSP to assembly wrapper + return (uint64_t)regs; +} diff --git a/src/kernel/syscall.h b/src/kernel/syscall.h index e09dbf1..b4401a4 100644 --- a/src/kernel/syscall.h +++ b/src/kernel/syscall.h @@ -8,6 +8,7 @@ // Forward declarations typedef struct Window Window; +typedef struct registers_t registers_t; // MSRs used for syscalls in x86_64 #define MSR_EFER 0xC0000080 @@ -38,7 +39,7 @@ typedef struct Window Window; #define FS_CMD_CHDIR 13 void syscall_init(void); -uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5); +uint64_t syscall_handler_c(registers_t *regs); // Mouse event helpers for WM void syscall_send_mouse_move_event(Window *win, int x, int y, uint8_t buttons); diff --git a/src/kernel/syscalls.asm b/src/kernel/syscalls.asm index 05f6f7b..b283a32 100644 --- a/src/kernel/syscalls.asm +++ b/src/kernel/syscalls.asm @@ -16,63 +16,63 @@ section .text syscall_entry: ; 1. Switch to Kernel Stack - ; Use scratch temporarily to pivot (Risk: Task switch here is rare but possible) mov [rel user_rsp_scratch], rsp mov rsp, [rel kernel_syscall_stack] - ; 2. Save User RSP on per-process kernel stack - push qword [rel user_rsp_scratch] - - ; 3. Save preserved registers (System V ABI) + ; 2. Build iretq frame (compatible with registers_t) + push 0x1B ; SS (User Data) + push qword [rel user_rsp_scratch] ; RSP + push r11 ; RFLAGS (captured by syscall) + push 0x23 ; CS (User Code) + push rcx ; RIP (return address from syscall) + + push 0 ; err_code + push 0 ; int_no (can be used for syscall vector) + + ; 3. Save all registers in registers_t order + push rax push rbx + push rcx + push rdx + push rsi + push rdi push rbp + push r8 + push r9 + push r10 + push r11 push r12 push r13 push r14 push r15 - - ; 4. Save RCX (RIP) and R11 (RFLAGS) - push rcx - push r11 - ; Shuffling for SYS V C ABI: - ; arg5: R9 (remains R9 as 6th arg in C) - ; arg4: R8 (was R9) - ; arg3: RCX (was R10) - ; arg2: RDX (was RSI) - ; arg1: RSI (was RDI) - ; num: RDI (was RAX) - - mov r9, r8 ; arg5 - mov r8, r10 ; arg4 - mov rcx, rdx ; arg3 - mov rdx, rsi ; arg2 - mov rsi, rdi ; arg1 - mov rdi, rax ; syscall_num - - ; 5. Call C handler + ; 4. Call C handler with registers_t* + mov rdi, rsp sti call syscall_handler_c cli - ; 6. Restore RCX and R11 - pop r11 - pop rcx + ; 5. Switch to the resulting RSP (might be different if task switched) + mov rsp, rax - ; 7. Restore preserved registers + ; 6. Restore and return via iretq pop r15 pop r14 pop r13 pop r12 + pop r11 + pop r10 + pop r9 + pop r8 pop rbp + pop rdi + pop rsi + pop rdx + pop rcx pop rbx - - ; 8. Restore User RSP from kernel stack - pop rsp - - ; 9. Return to User Mode (sysret) - or r11, 0x200 ; Force Interrupts enabled - o64 sysret + pop rax + add rsp, 16 ; drop int_no/err_code + iretq section .bss global kernel_syscall_stack