mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
memory fixes
This commit is contained in:
parent
a4e0a42042
commit
c5c77ce734
12 changed files with 156 additions and 105 deletions
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue