Memory bug fix

This commit is contained in:
boreddevnl
2026-03-01 00:52:25 +01:00
parent 8afb488539
commit a4e0a42042
18 changed files with 174 additions and 213 deletions

BIN
src/kernel/.DS_Store vendored

Binary file not shown.

View File

@@ -286,18 +286,18 @@ static uint32_t parse_color(const char *s) {
}
static void cmd_init_config_defaults(void) {
shell_config.prompt_drive_color = 0xFFCCCCCC; // Default light gray
shell_config.prompt_drive_color = 0xFFFFFFFF; // Default light gray
shell_config.prompt_colon_color = 0xFFCCCCCC;
shell_config.prompt_dir_color = 0xFF569CD6; // Blue
shell_config.prompt_op_color = 0xFFCCCCCC;
shell_config.prompt_op_char = '>';
shell_config.default_text_color = 0xFFCCCCCC;
shell_config.default_text_color = 0xFFFFFFFF; // White
shell_config.bg_color = 0xFF1E1E1E; // Dark background
shell_config.cursor_color = 0xFFFFFFFF;
shell_config.show_drive = true;
shell_config.show_dir = true;
shell_config.dir_color = 0xFF569CD6;
shell_config.file_color = 0xFFCCCCCC;
shell_config.file_color = 0xFFFFFFFF;
shell_config.size_color = 0xFF6A9955; // Green
shell_config.error_color = 0xFFFF4444; // Red
shell_config.success_color = 0xFF6A9955;

View File

@@ -9,6 +9,7 @@ static ipv4_address_t dns_result_ip;
static bool dns_resolved = false;
void dns_handle_response(void *data, uint16_t len) {
(void)len;
dns_header_t *dns = (dns_header_t*)data;
if ((ntohs(dns->flags) & 0x8000) == 0) return; // Not a response
@@ -30,6 +31,9 @@ void dns_handle_response(void *data, uint16_t len) {
uint32_t ttl = ntohl(*(uint32_t*)p); p += 4;
uint16_t dlen = ntohs(*(uint16_t*)p); p += 2;
(void)class;
(void)ttl;
if (type == 1 && dlen == 4) { // A Record
dns_result_ip.bytes[0] = p[0];
dns_result_ip.bytes[1] = p[1];

View File

@@ -114,42 +114,9 @@ void kmain(void) {
serial_write_hex(kernel_virt_base);
serial_write("\n");
uint64_t heap_phys_addr = 0;
size_t heap_size = 0;
if (memmap_request.response != NULL) {
serial_write("[DEBUG] Memory Map entries: ");
serial_write_num(memmap_request.response->entry_count);
serial_write("\n");
for (uint64_t i = 0; i < memmap_request.response->entry_count; i++) {
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
serial_write("[DEBUG] Map entry ");
serial_write_num(i);
serial_write(": base=");
serial_write_hex(entry->base);
serial_write(" len=");
serial_write_hex(entry->length);
serial_write(" type=");
serial_write_num(entry->type);
serial_write("\n");
if (entry->type == LIMINE_MEMMAP_USABLE) {
if (entry->length > heap_size) {
heap_size = entry->length;
heap_phys_addr = entry->base;
}
}
}
}
if (heap_size > 512 * 1024 * 1024) heap_size = 512 * 1024 * 1024;
if (heap_phys_addr != 0) {
serial_write("[DEBUG] Selected heap base (Phys): 0x");
serial_write_hex(heap_phys_addr);
serial_write(", Size: ");
serial_write_num(heap_size / 1024 / 1024);
serial_write(" MB\n");
memory_manager_init_at((void*)p2v(heap_phys_addr), heap_size);
// The memory manager will now scan the memory map and manage all usable regions.
memory_manager_init_from_memmap(memmap_request.response);
serial_write("[DEBUG] memory_manager_init OK\n");
} else {
serial_write("[DEBUG] ERROR: No usable memory for heap! Check Limine memmap.\n");
@@ -196,23 +163,14 @@ void kmain(void) {
serial_write("\n");
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
struct limine_file *mod = module_request.response->modules[i];
serial_write("[DEBUG] Found module: ");
serial_write(mod->path);
serial_write(" adr=0x");
serial_write_hex((uint64_t)mod->address);
serial_write(" size=");
serial_write_num(mod->size);
serial_write("\n");
const char *clean_path = mod->path;
// Strip boot():/ or boot:/// prefixes common in different Limine versions
if (fs_starts_with(clean_path, "boot():")) clean_path += 7;
else if (fs_starts_with(clean_path, "boot:///")) clean_path += 8;
serial_write("[DEBUG] Stripped module path: ");
serial_write(clean_path);
serial_write("\n");
FAT32_FileHandle *fh = fat32_open(clean_path, "w");
if (fh && fh->valid) {

View File

@@ -53,7 +53,7 @@ void create_man_entries(void) {
write_man_file("mv", "MV - Move or rename file\n\nUsage: mv <source> <dest>\n\nMoves or renames a file or directory.");
write_man_file("cp", "CP - Copy file\n\nUsage: cp <source> <dest>\n\nCopies a file from the source path to the destination path.");
write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch <filename>\n\nCreates a new empty file if it doesn't exist.");
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into ELF executables.");
write_man_file("cc", "CC - C Compiler\n\nUsage: cc <file.c>\n\nThe BoredOS C Compiler. Compiles C source files into executables. (execute these with ./>file<)");
write_man_file("crash", "CRASH - Trigger kernel exception\n\nUsage: crash\n\nIntentionally triggers a null pointer dereference to test handlers.");
write_man_file("boredver", "BOREDVER - Show OS version\n\nUsage: boredver\n\nDisplays current BoredOS version and kernel build information.");
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");

View File

@@ -2,11 +2,13 @@
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "memory_manager.h"
#include "io.h"
#include <stdint.h>
#include "limine.h"
#include "platform.h"
// --- Internal State ---
static uint8_t *memory_pool = NULL;
// memory_pool is no longer a single pointer, as we now manage multiple regions.
// The block_list will contain all information about free and allocated regions.
static size_t memory_pool_size = 0;
static MemBlock block_list[MAX_ALLOCATIONS];
static int block_count = 0;
@@ -15,6 +17,9 @@ static size_t peak_allocated = 0;
static uint32_t allocation_counter = 0;
static bool initialized = false;
extern void serial_write(const char *str);
extern void serial_write_num(uint32_t n);
// --- Helper Functions ---
// Simple memset for internal use
@@ -53,59 +58,8 @@ static uint32_t get_timestamp(void) {
return tick++;
}
// Find free space in memory pool with alignment
static void* find_free_space_aligned(size_t size, size_t alignment) {
size_t offset = 0;
// Ensure 8-byte minimum alignment for regular malloc if 0 is passed
if (alignment == 0) alignment = 8;
while (offset + size <= memory_pool_size) {
// Align offset
if ((uint64_t)((uint8_t*)memory_pool + offset) % alignment != 0) {
size_t diff = alignment - ((uint64_t)((uint8_t*)memory_pool + offset) % alignment);
offset += diff;
}
if (offset + size > memory_pool_size) break;
bool space_free = true;
// Check if this range is free
for (int i = 0; i < block_count; i++) {
if (!block_list[i].allocated) continue;
void *block_start = block_list[i].address;
void *block_end = (uint8_t *)block_start + block_list[i].size;
void *check_start = (uint8_t *)memory_pool + offset;
void *check_end = (uint8_t *)check_start + size;
// Check for overlap
if (check_start < block_end && check_end > block_start) {
space_free = false;
// Move offset past this block
offset = (size_t)((uint8_t *)block_end - (uint8_t *)memory_pool);
break;
}
}
if (space_free) {
return (uint8_t *)memory_pool + offset;
}
}
return NULL;
}
static void* find_free_space(size_t size) {
return find_free_space_aligned(size, 8);
}
// Calculate fragmentation
static size_t calculate_fragmentation(void) {
if (total_allocated == 0) return 0;
// Sort blocks by address
// Sorts the block list by address. This is crucial for efficient merging of free blocks.
static void sort_block_list() {
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) {
@@ -115,34 +69,31 @@ static size_t calculate_fragmentation(void) {
}
}
}
// Count gaps between allocated blocks
size_t total_gaps = 0;
void *pool_end = (uint8_t *)memory_pool + memory_pool_size;
void *current_end = memory_pool;
}
// Calculate fragmentation
static size_t calculate_fragmentation(void) {
size_t total_free = memory_pool_size - total_allocated;
if (total_free == 0) return 0;
size_t largest_free = 0;
for (int i = 0; i < block_count; i++) {
if (!block_list[i].allocated) continue;
if (block_list[i].address > current_end) {
total_gaps += (uintptr_t)block_list[i].address - (uintptr_t)current_end;
if (!block_list[i].allocated && block_list[i].size > largest_free) {
largest_free = block_list[i].size;
}
current_end = (uint8_t *)block_list[i].address + block_list[i].size;
}
if (total_allocated == 0) return 0;
return (total_gaps * 100) / total_allocated;
// Fragmentation = 1 - (Largest Free / Total Free)
size_t frag_percent = 100 - ((largest_free * 100) / total_free);
return frag_percent;
}
// --- Public API ---
void memory_manager_init_at(void *pool_address, size_t pool_size) {
if (initialized) return;
memory_pool = (uint8_t *)pool_address;
memory_pool_size = pool_size;
void memory_manager_init_from_memmap(struct limine_memmap_response *memmap) {
if (initialized || !memmap) return;
// Clear metadata
mem_memset(block_list, 0, sizeof(block_list));
@@ -150,77 +101,115 @@ void memory_manager_init_at(void *pool_address, size_t pool_size) {
total_allocated = 0;
peak_allocated = 0;
allocation_counter = 0;
// Create initial free block representing entire pool
block_list[0].address = memory_pool;
block_list[0].size = memory_pool_size;
block_list[0].allocated = false;
block_list[0].allocation_id = 0;
block_count = 1;
memory_pool_size = 0;
for (uint64_t i = 0; i < memmap->entry_count; i++) {
struct limine_memmap_entry *entry = memmap->entries[i];
if (entry->type == LIMINE_MEMMAP_USABLE) {
uint64_t base = entry->base;
uint64_t size = entry->length;
// Avoid low memory below 1MB which is used for boot/kernel structures
if (base < 0x100000) {
if (base + size <= 0x100000) {
continue; // Skip this low memory block entirely
}
uint64_t diff = 0x100000 - base;
base = 0x100000;
size -= diff;
}
if (size < 4096) continue; // Ignore small fragments
if (block_count >= MAX_ALLOCATIONS) {
serial_write("[MEM] WARN: Exceeded MAX_ALLOCATIONS while parsing memmap.\n");
break;
}
block_list[block_count].address = (void*)p2v(base);
block_list[block_count].size = size;
block_list[block_count].allocated = false;
block_list[block_count].allocation_id = 0;
block_count++;
memory_pool_size += size;
}
}
sort_block_list();
initialized = true;
}
void memory_manager_init_with_size(size_t pool_size) {
if (initialized) return;
}
void memory_manager_init(void) {
memory_manager_init_with_size(DEFAULT_POOL_SIZE);
serial_write("[MEM] Total usable memory: ");
serial_write_num(memory_pool_size / 1024 / 1024);
serial_write(" MB\n");
}
void* kmalloc_aligned(size_t size, size_t alignment) {
if (!initialized) {
memory_manager_init();
}
if (!initialized || size == 0) return NULL;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (size == 0 || size > memory_pool_size) {
asm volatile("push %0; popfq" : : "r"(rflags));
return NULL;
if (alignment == 0) alignment = 8;
size = (size + 7) & ~7ULL; // Ensure size is multiple of 8
for (int i = 0; i < block_count; i++) {
if (block_list[i].allocated) continue;
uintptr_t block_start = (uintptr_t)block_list[i].address;
size_t block_size = block_list[i].size;
uintptr_t aligned_addr = block_start;
if (aligned_addr % alignment != 0) {
aligned_addr = (aligned_addr + alignment - 1) & ~(alignment - 1);
}
size_t padding = aligned_addr - block_start;
if (block_size >= size + padding) {
void* ptr = (void*)aligned_addr;
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--;
}
// 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++;
// 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++;
}
}
sort_block_list();
total_allocated += size;
if (total_allocated > peak_allocated) peak_allocated = total_allocated;
mem_memset(ptr, 0, size);
asm volatile("push %0; popfq" : : "r"(rflags));
return ptr;
}
}
if (total_allocated + size > memory_pool_size) {
asm volatile("push %0; popfq" : : "r"(rflags));
return NULL;
}
// Find free space with alignment
void *ptr = find_free_space_aligned(size, alignment);
if (ptr == NULL) {
asm volatile("push %0; popfq" : : "r"(rflags));
return NULL;
}
// Add block entry
if (block_count >= MAX_ALLOCATIONS) {
asm volatile("push %0; popfq" : : "r"(rflags));
return NULL;
}
allocation_counter++;
int idx = block_count++;
block_list[idx].address = ptr;
block_list[idx].size = size;
block_list[idx].allocated = true;
block_list[idx].allocation_id = allocation_counter;
block_list[idx].timestamp = get_timestamp();
total_allocated += size;
if (total_allocated > peak_allocated) {
peak_allocated = total_allocated;
}
// Clear memory
mem_memset(ptr, 0, size);
asm volatile("push %0; popfq" : : "r"(rflags));
return ptr;
return NULL;
}
void* kmalloc(size_t size) {
@@ -228,36 +217,55 @@ void* kmalloc(size_t size) {
}
void kfree(void *ptr) {
if (ptr == NULL || !initialized) {
return;
}
if (ptr == NULL || !initialized) return;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
// Find and free the block
int block_idx = -1;
for (int i = 0; i < block_count; i++) {
if (block_list[i].allocated && block_list[i].address == ptr) {
total_allocated -= block_list[i].size;
block_list[i].allocated = false;
// Compact: remove freed entry and shift remaining
for (int j = i; j < block_count - 1; j++) {
block_list[j] = block_list[j + 1];
}
block_idx = i;
break;
}
}
if (block_idx == -1) {
asm volatile("push %0; popfq" : : "r"(rflags));
return;
}
total_allocated -= block_list[block_idx].size;
block_list[block_idx].allocated = false;
// Merge with next block if it's free and physically adjacent
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;
if (current_end == next_start) {
block_list[block_idx].size += block_list[block_idx + 1].size;
for (int i = block_idx + 1; i < block_count - 1; i++) block_list[i] = block_list[i + 1];
block_count--;
}
}
// Merge with previous block if it's free and physically adjacent
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;
if (prev_end == current_start) {
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;
}
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
void* krealloc(void *ptr, size_t new_size) {
if (!initialized) {
memory_manager_init();
}
if (new_size == 0) {
kfree(ptr);
return NULL;
@@ -267,24 +275,18 @@ void* krealloc(void *ptr, size_t new_size) {
return kmalloc(new_size);
}
// Find the block
for (int i = 0; i < block_count; i++) {
if (block_list[i].allocated && block_list[i].address == ptr) {
if (block_list[i].size >= new_size) {
// Allocation is large enough
return ptr;
}
// Need to allocate new space
void *new_ptr = kmalloc(new_size);
if (new_ptr == NULL) {
return NULL;
}
// Copy data
mem_memmove(new_ptr, ptr, block_list[i].size);
// Free old pointer
kfree(ptr);
return new_ptr;
@@ -468,10 +470,7 @@ void memory_reset_peak(void) {
bool memory_is_valid_ptr(void *ptr) {
if (ptr == NULL) return false;
void *pool_start = memory_pool;
void *pool_end = (uint8_t *)memory_pool + memory_pool_size;
if (ptr < pool_start || ptr >= pool_end) {
if (!initialized) {
return false;
}

View File

@@ -7,6 +7,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "limine.h"
// Memory Manager Configuration
#define DEFAULT_POOL_SIZE (128 * 1024 * 1024) // 128MB default
@@ -36,9 +37,7 @@ typedef struct {
} MemStats;
// Public API
void memory_manager_init(void);
void memory_manager_init_with_size(size_t pool_size);
void memory_manager_init_at(void *pool_address, size_t pool_size);
void memory_manager_init_from_memmap(struct limine_memmap_response *memmap);
// Allocation/Deallocation
void* kmalloc(size_t size);