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

View file

@ -135,6 +135,7 @@ clean:
run: $(ISO_IMAGE)
qemu-system-x86_64 -m 2G -serial stdio -cdrom $< -boot d \
-m 4G \
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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