memory fixes

This commit is contained in:
boreddevnl 2026-03-01 04:21:04 +01:00
parent a4e0a42042
commit c5c77ce734
12 changed files with 156 additions and 105 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -29,9 +29,9 @@ isr%2_wrapper:
push rbx push rbx
push rcx push rcx
push rdx push rdx
push rbp
push rdi
push rsi push rsi
push rdi
push rbp
push r8 push r8
push r9 push r9
push r10 push r10
@ -57,9 +57,9 @@ isr%2_wrapper:
pop r10 pop r10
pop r9 pop r9
pop r8 pop r8
pop rsi
pop rdi
pop rbp pop rbp
pop rdi
pop rsi
pop rdx pop rdx
pop rcx pop rcx
pop rbx pop rbx
@ -134,9 +134,9 @@ exception_common:
push rbx push rbx
push rcx push rcx
push rdx push rdx
push rbp
push rdi
push rsi push rsi
push rdi
push rbp
push r8 push r8
push r9 push r9
push r10 push r10
@ -163,9 +163,9 @@ exception_common:
pop r10 pop r10
pop r9 pop r9
pop r8 pop r8
pop rsi
pop rdi
pop rbp pop rbp
pop rdi
pop rsi
pop rdx pop rdx
pop rcx pop rcx
pop rbx pop rbx

View file

@ -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. // Sorts the block list by address. This is crucial for efficient merging of free blocks.
static void sort_block_list() { static void sort_block_list() {
bool swapped;
for (int i = 0; i < block_count - 1; i++) { for (int i = 0; i < block_count - 1; i++) {
for (int j = i + 1; j < block_count; j++) { swapped = false;
if ((uintptr_t)block_list[i].address > (uintptr_t)block_list[j].address) { for (int j = 0; j < block_count - i - 1; j++) {
MemBlock tmp = block_list[i]; if ((uintptr_t)block_list[j].address > (uintptr_t)block_list[j + 1].address) {
block_list[i] = block_list[j]; MemBlock tmp = block_list[j];
block_list[j] = tmp; block_list[j] = block_list[j + 1];
block_list[j + 1] = tmp;
swapped = true;
} }
} }
if (!swapped) break;
} }
} }
@ -167,19 +171,24 @@ void* kmalloc_aligned(size_t size, size_t alignment) {
size_t padding = aligned_addr - block_start; size_t padding = aligned_addr - block_start;
if (block_size >= size + padding) { 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); size_t remaining_size = block_size - (size + padding);
if (remaining_size > 0) {
// The original free block becomes the trailing free part. needed_slots++;
block_list[i].address = (void*)(aligned_addr + size); } else {
block_list[i].size = remaining_size; // The current slot will be reused for the allocation.
if (remaining_size == 0) {
for (int j = i; j < block_count - 1; j++) block_list[j] = block_list[j+1];
block_count--;
} }
// Create a new block for the allocation. if (block_count + needed_slots > MAX_ALLOCATIONS) {
if (block_count >= MAX_ALLOCATIONS) continue; 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].address = ptr;
block_list[block_count].size = size; block_list[block_count].size = size;
block_list[block_count].allocated = true; block_list[block_count].allocated = true;
@ -187,15 +196,24 @@ void* kmalloc_aligned(size_t size, size_t alignment) {
block_list[block_count].timestamp = get_timestamp(); block_list[block_count].timestamp = get_timestamp();
block_count++; block_count++;
// Create a new block for the leading padding if it exists. 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();
}
if (padding > 0) { if (padding > 0) {
if (block_count < MAX_ALLOCATIONS) {
block_list[block_count].address = (void*)block_start; block_list[block_count].address = (void*)block_start;
block_list[block_count].size = padding; block_list[block_count].size = padding;
block_list[block_count].allocated = false; block_list[block_count].allocated = false;
block_list[block_count].allocation_id = 0;
block_count++; block_count++;
} }
}
sort_block_list(); sort_block_list();
@ -237,8 +255,20 @@ void kfree(void *ptr) {
total_allocated -= block_list[block_idx].size; total_allocated -= block_list[block_idx].size;
block_list[block_idx].allocated = false; 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) { 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 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; 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) { 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 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; 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; 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]; for (int i = block_idx; i < block_count - 1; i++) block_list[i] = block_list[i + 1];
block_count--; 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 memory_get_stats(void) {
MemStats stats; MemStats stats;
mem_memset(&stats, 0, sizeof(MemStats));
stats.total_memory = memory_pool_size; stats.total_memory = memory_pool_size;
stats.used_memory = total_allocated; stats.used_memory = total_allocated;

View file

@ -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) { 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;
}
}
if (!new_proc) return NULL;
process_t *new_proc = &processes[process_count];
new_proc->pid = next_pid++; new_proc->pid = next_pid++;
new_proc->is_user = true; 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->user_stack_alloc = stack;
new_proc->rsp = (uint64_t)stack_ptr; new_proc->rsp = (uint64_t)stack_ptr;
// We only increment process_count after success // Slot is already counted in process_count if new, or reused.
process_count++;
// Add to linked list // Add to linked list
new_proc->next = current_process->next; new_proc->next = current_process->next;
@ -291,13 +300,17 @@ uint64_t process_schedule(uint64_t current_rsp) {
} }
uint64_t process_terminate_current(void) { 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 // 1. Cleanup side effects
extern Window win_cmd; extern Window win_cmd;
if (current_process->ui_window && (current_process->ui_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); wm_remove_window((Window *)current_process->ui_window);
current_process->ui_window = NULL; current_process->ui_window = NULL;
} }
@ -324,13 +337,14 @@ uint64_t process_terminate_current(void) {
if (prev == current_process) { if (prev == current_process) {
// Only one process (should be kernel), cannot terminate. // Only one process (should be kernel), cannot terminate.
asm volatile("push %0; popfq" : : "r"(rflags));
return to_delete->rsp; return to_delete->rsp;
} }
prev->next = to_delete->next; prev->next = to_delete->next;
current_process = to_delete->next; current_process = to_delete->next;
// Mark slot as freeish (simple version) // Mark slot as free
to_delete->pid = 0xFFFFFFFF; to_delete->pid = 0xFFFFFFFF;
// 4. Load context for the NEXT process // 4. Load context for the NEXT process
@ -343,13 +357,17 @@ uint64_t process_terminate_current(void) {
paging_switch_directory(current_process->pml4_phys); paging_switch_directory(current_process->pml4_phys);
// 5. Actually free the memory (after switching state to avoid issues) // 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); if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
// NOTE: In a real system we would also free all physical pages // Clear pointers to avoid double-free during slot reuse
// used by the user page table. For now we just free the stacks. to_delete->user_stack_alloc = NULL;
to_delete->kernel_stack_alloc = NULL; // Leak the small kernel stack for safety
return current_process->rsp; 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) { void process_push_gui_event(process_t *proc, gui_event_t *ev) {

View file

@ -14,7 +14,7 @@
struct FAT32_FileHandle; struct FAT32_FileHandle;
// Registers saved on the stack by interrupts/exceptions // 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 r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax; uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t int_no, err_code; uint64_t int_no, err_code;

View file

@ -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 cmd_write(const char *str);
extern void serial_write(const char *str); extern void serial_write(const char *str);
extern void cmd_process_finished(void);
if (syscall_num == 1) { // SYS_WRITE if (syscall_num == 1) { // SYS_WRITE
cmd_write((const char*)arg2); 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 } else if (syscall_num == 3) { // SYS_GUI
int cmd = (int)arg1; int cmd = (int)arg1;
process_t *proc = process_get_current(); 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); serial_write((const char *)arg2);
return 0; return 0;
} else if (syscall_num == 10) { // SYS_KILL } else if (syscall_num == 10) { // SYS_KILL
// Simplified kill: just terminate current for now return 0; // Handled in outer
uint64_t next_rsp = process_terminate_current();
extern void context_switch_to(uint64_t rsp);
context_switch_to(next_rsp);
while(1);
} else if (syscall_num == 9) { // SYS_SBRK } else if (syscall_num == 9) { // SYS_SBRK
int incr = (int)arg1; int incr = (int)arg1;
process_t *proc = process_get_current(); 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; 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;
}

View file

@ -8,6 +8,7 @@
// Forward declarations // Forward declarations
typedef struct Window Window; typedef struct Window Window;
typedef struct registers_t registers_t;
// MSRs used for syscalls in x86_64 // MSRs used for syscalls in x86_64
#define MSR_EFER 0xC0000080 #define MSR_EFER 0xC0000080
@ -38,7 +39,7 @@ typedef struct Window Window;
#define FS_CMD_CHDIR 13 #define FS_CMD_CHDIR 13
void syscall_init(void); 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 // Mouse event helpers for WM
void syscall_send_mouse_move_event(Window *win, int x, int y, uint8_t buttons); void syscall_send_mouse_move_event(Window *win, int x, int y, uint8_t buttons);

View file

@ -16,63 +16,63 @@ section .text
syscall_entry: syscall_entry:
; 1. Switch to Kernel Stack ; 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 [rel user_rsp_scratch], rsp
mov rsp, [rel kernel_syscall_stack] mov rsp, [rel kernel_syscall_stack]
; 2. Save User RSP on per-process kernel stack ; 2. Build iretq frame (compatible with registers_t)
push qword [rel user_rsp_scratch] 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)
; 3. Save preserved registers (System V ABI) 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 rbx
push rcx
push rdx
push rsi
push rdi
push rbp push rbp
push r8
push r9
push r10
push r11
push r12 push r12
push r13 push r13
push r14 push r14
push r15 push r15
; 4. Save RCX (RIP) and R11 (RFLAGS) ; 4. Call C handler with registers_t*
push rcx mov rdi, rsp
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
sti sti
call syscall_handler_c call syscall_handler_c
cli cli
; 6. Restore RCX and R11 ; 5. Switch to the resulting RSP (might be different if task switched)
pop r11 mov rsp, rax
pop rcx
; 7. Restore preserved registers ; 6. Restore and return via iretq
pop r15 pop r15
pop r14 pop r14
pop r13 pop r13
pop r12 pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx pop rbx
pop rax
; 8. Restore User RSP from kernel stack add rsp, 16 ; drop int_no/err_code
pop rsp iretq
; 9. Return to User Mode (sysret)
or r11, 0x200 ; Force Interrupts enabled
o64 sysret
section .bss section .bss
global kernel_syscall_stack global kernel_syscall_stack