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 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

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.
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;

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) {
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->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.
// 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
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) {

View file

@ -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;

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 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;
}

View file

@ -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);

View file

@ -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]
; 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)
; 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 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