mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
Memory bug fix
This commit is contained in:
parent
8afb488539
commit
a4e0a42042
18 changed files with 174 additions and 213 deletions
1
Makefile
1
Makefile
|
|
@ -135,6 +135,7 @@ clean:
|
||||||
|
|
||||||
run: $(ISO_IMAGE)
|
run: $(ISO_IMAGE)
|
||||||
qemu-system-x86_64 -m 2G -serial stdio -cdrom $< -boot d \
|
qemu-system-x86_64 -m 2G -serial stdio -cdrom $< -boot d \
|
||||||
|
-m 4G \
|
||||||
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
-audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \
|
||||||
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
|
-netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \
|
||||||
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
-vga std -global VGA.xres=1920 -global VGA.yres=1080 \
|
||||||
|
|
|
||||||
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
Binary file not shown.
BIN
build/dns.o
BIN
build/dns.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/fat32.o
BIN
build/fat32.o
Binary file not shown.
BIN
build/icmp.o
BIN
build/icmp.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/kernel/.DS_Store
vendored
BIN
src/kernel/.DS_Store
vendored
Binary file not shown.
|
|
@ -286,18 +286,18 @@ static uint32_t parse_color(const char *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cmd_init_config_defaults(void) {
|
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_colon_color = 0xFFCCCCCC;
|
||||||
shell_config.prompt_dir_color = 0xFF569CD6; // Blue
|
shell_config.prompt_dir_color = 0xFF569CD6; // Blue
|
||||||
shell_config.prompt_op_color = 0xFFCCCCCC;
|
shell_config.prompt_op_color = 0xFFCCCCCC;
|
||||||
shell_config.prompt_op_char = '>';
|
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.bg_color = 0xFF1E1E1E; // Dark background
|
||||||
shell_config.cursor_color = 0xFFFFFFFF;
|
shell_config.cursor_color = 0xFFFFFFFF;
|
||||||
shell_config.show_drive = true;
|
shell_config.show_drive = true;
|
||||||
shell_config.show_dir = true;
|
shell_config.show_dir = true;
|
||||||
shell_config.dir_color = 0xFF569CD6;
|
shell_config.dir_color = 0xFF569CD6;
|
||||||
shell_config.file_color = 0xFFCCCCCC;
|
shell_config.file_color = 0xFFFFFFFF;
|
||||||
shell_config.size_color = 0xFF6A9955; // Green
|
shell_config.size_color = 0xFF6A9955; // Green
|
||||||
shell_config.error_color = 0xFFFF4444; // Red
|
shell_config.error_color = 0xFFFF4444; // Red
|
||||||
shell_config.success_color = 0xFF6A9955;
|
shell_config.success_color = 0xFF6A9955;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ static ipv4_address_t dns_result_ip;
|
||||||
static bool dns_resolved = false;
|
static bool dns_resolved = false;
|
||||||
|
|
||||||
void dns_handle_response(void *data, uint16_t len) {
|
void dns_handle_response(void *data, uint16_t len) {
|
||||||
|
(void)len;
|
||||||
dns_header_t *dns = (dns_header_t*)data;
|
dns_header_t *dns = (dns_header_t*)data;
|
||||||
if ((ntohs(dns->flags) & 0x8000) == 0) return; // Not a response
|
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;
|
uint32_t ttl = ntohl(*(uint32_t*)p); p += 4;
|
||||||
uint16_t dlen = ntohs(*(uint16_t*)p); p += 2;
|
uint16_t dlen = ntohs(*(uint16_t*)p); p += 2;
|
||||||
|
|
||||||
|
(void)class;
|
||||||
|
(void)ttl;
|
||||||
|
|
||||||
if (type == 1 && dlen == 4) { // A Record
|
if (type == 1 && dlen == 4) { // A Record
|
||||||
dns_result_ip.bytes[0] = p[0];
|
dns_result_ip.bytes[0] = p[0];
|
||||||
dns_result_ip.bytes[1] = p[1];
|
dns_result_ip.bytes[1] = p[1];
|
||||||
|
|
|
||||||
|
|
@ -114,42 +114,9 @@ void kmain(void) {
|
||||||
serial_write_hex(kernel_virt_base);
|
serial_write_hex(kernel_virt_base);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
uint64_t heap_phys_addr = 0;
|
|
||||||
size_t heap_size = 0;
|
|
||||||
if (memmap_request.response != NULL) {
|
if (memmap_request.response != NULL) {
|
||||||
serial_write("[DEBUG] Memory Map entries: ");
|
// The memory manager will now scan the memory map and manage all usable regions.
|
||||||
serial_write_num(memmap_request.response->entry_count);
|
memory_manager_init_from_memmap(memmap_request.response);
|
||||||
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);
|
|
||||||
serial_write("[DEBUG] memory_manager_init OK\n");
|
serial_write("[DEBUG] memory_manager_init OK\n");
|
||||||
} else {
|
} else {
|
||||||
serial_write("[DEBUG] ERROR: No usable memory for heap! Check Limine memmap.\n");
|
serial_write("[DEBUG] ERROR: No usable memory for heap! Check Limine memmap.\n");
|
||||||
|
|
@ -197,22 +164,13 @@ void kmain(void) {
|
||||||
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
||||||
struct limine_file *mod = module_request.response->modules[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;
|
const char *clean_path = mod->path;
|
||||||
// Strip boot():/ or boot:/// prefixes common in different Limine versions
|
// Strip boot():/ or boot:/// prefixes common in different Limine versions
|
||||||
if (fs_starts_with(clean_path, "boot():")) clean_path += 7;
|
if (fs_starts_with(clean_path, "boot():")) clean_path += 7;
|
||||||
else if (fs_starts_with(clean_path, "boot:///")) clean_path += 8;
|
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");
|
FAT32_FileHandle *fh = fat32_open(clean_path, "w");
|
||||||
if (fh && fh->valid) {
|
if (fh && fh->valid) {
|
||||||
|
|
|
||||||
|
|
@ -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("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("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("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("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("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.");
|
write_man_file("meminfo", "MEMINFO - Memory usage stats\n\nUsage: meminfo\n\nDisplays current physical and virtual memory allocation statistics.");
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
||||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
// 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.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
#include "io.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "limine.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
// --- Internal State ---
|
// --- 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 size_t memory_pool_size = 0;
|
||||||
static MemBlock block_list[MAX_ALLOCATIONS];
|
static MemBlock block_list[MAX_ALLOCATIONS];
|
||||||
static int block_count = 0;
|
static int block_count = 0;
|
||||||
|
|
@ -15,6 +17,9 @@ static size_t peak_allocated = 0;
|
||||||
static uint32_t allocation_counter = 0;
|
static uint32_t allocation_counter = 0;
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
|
|
||||||
|
extern void serial_write(const char *str);
|
||||||
|
extern void serial_write_num(uint32_t n);
|
||||||
|
|
||||||
// --- Helper Functions ---
|
// --- Helper Functions ---
|
||||||
|
|
||||||
// Simple memset for internal use
|
// Simple memset for internal use
|
||||||
|
|
@ -53,59 +58,8 @@ static uint32_t get_timestamp(void) {
|
||||||
return tick++;
|
return tick++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find free space in memory pool with alignment
|
// Sorts the block list by address. This is crucial for efficient merging of free blocks.
|
||||||
static void* find_free_space_aligned(size_t size, size_t alignment) {
|
static void sort_block_list() {
|
||||||
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
|
|
||||||
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++) {
|
for (int j = i + 1; j < block_count; j++) {
|
||||||
if ((uintptr_t)block_list[i].address > (uintptr_t)block_list[j].address) {
|
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
|
// Calculate fragmentation
|
||||||
size_t total_gaps = 0;
|
static size_t calculate_fragmentation(void) {
|
||||||
void *pool_end = (uint8_t *)memory_pool + memory_pool_size;
|
size_t total_free = memory_pool_size - total_allocated;
|
||||||
|
if (total_free == 0) return 0;
|
||||||
void *current_end = memory_pool;
|
|
||||||
|
|
||||||
|
size_t largest_free = 0;
|
||||||
for (int i = 0; i < block_count; i++) {
|
for (int i = 0; i < block_count; i++) {
|
||||||
if (!block_list[i].allocated) continue;
|
if (!block_list[i].allocated && block_list[i].size > largest_free) {
|
||||||
|
largest_free = block_list[i].size;
|
||||||
if (block_list[i].address > current_end) {
|
|
||||||
total_gaps += (uintptr_t)block_list[i].address - (uintptr_t)current_end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
current_end = (uint8_t *)block_list[i].address + block_list[i].size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_allocated == 0) return 0;
|
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 ---
|
// --- Public API ---
|
||||||
|
|
||||||
void memory_manager_init_at(void *pool_address, size_t pool_size) {
|
void memory_manager_init_from_memmap(struct limine_memmap_response *memmap) {
|
||||||
if (initialized) return;
|
if (initialized || !memmap) return;
|
||||||
|
|
||||||
memory_pool = (uint8_t *)pool_address;
|
|
||||||
memory_pool_size = pool_size;
|
|
||||||
|
|
||||||
// Clear metadata
|
// Clear metadata
|
||||||
mem_memset(block_list, 0, sizeof(block_list));
|
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;
|
total_allocated = 0;
|
||||||
peak_allocated = 0;
|
peak_allocated = 0;
|
||||||
allocation_counter = 0;
|
allocation_counter = 0;
|
||||||
|
memory_pool_size = 0;
|
||||||
|
|
||||||
// Create initial free block representing entire pool
|
for (uint64_t i = 0; i < memmap->entry_count; i++) {
|
||||||
block_list[0].address = memory_pool;
|
struct limine_memmap_entry *entry = memmap->entries[i];
|
||||||
block_list[0].size = memory_pool_size;
|
|
||||||
block_list[0].allocated = false;
|
|
||||||
block_list[0].allocation_id = 0;
|
|
||||||
block_count = 1;
|
|
||||||
|
|
||||||
|
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;
|
initialized = true;
|
||||||
}
|
serial_write("[MEM] Total usable memory: ");
|
||||||
|
serial_write_num(memory_pool_size / 1024 / 1024);
|
||||||
void memory_manager_init_with_size(size_t pool_size) {
|
serial_write(" MB\n");
|
||||||
|
|
||||||
if (initialized) return;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void memory_manager_init(void) {
|
|
||||||
memory_manager_init_with_size(DEFAULT_POOL_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void* kmalloc_aligned(size_t size, size_t alignment) {
|
void* kmalloc_aligned(size_t size, size_t alignment) {
|
||||||
if (!initialized) {
|
if (!initialized || size == 0) return NULL;
|
||||||
memory_manager_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
if (size == 0 || size > memory_pool_size) {
|
if (alignment == 0) alignment = 8;
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
size = (size + 7) & ~7ULL; // Ensure size is multiple of 8
|
||||||
return NULL;
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_allocated + size > memory_pool_size) {
|
size_t padding = aligned_addr - block_start;
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
|
||||||
return NULL;
|
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--;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find free space with alignment
|
// Create a new block for the allocation.
|
||||||
void *ptr = find_free_space_aligned(size, alignment);
|
if (block_count >= MAX_ALLOCATIONS) continue;
|
||||||
if (ptr == NULL) {
|
block_list[block_count].address = ptr;
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
block_list[block_count].size = size;
|
||||||
return NULL;
|
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++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add block entry
|
sort_block_list();
|
||||||
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;
|
total_allocated += size;
|
||||||
if (total_allocated > peak_allocated) {
|
if (total_allocated > peak_allocated) peak_allocated = total_allocated;
|
||||||
peak_allocated = total_allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear memory
|
|
||||||
mem_memset(ptr, 0, size);
|
mem_memset(ptr, 0, size);
|
||||||
|
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return ptr;
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* kmalloc(size_t size) {
|
void* kmalloc(size_t size) {
|
||||||
|
|
@ -228,36 +217,55 @@ void* kmalloc(size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void kfree(void *ptr) {
|
void kfree(void *ptr) {
|
||||||
if (ptr == NULL || !initialized) {
|
if (ptr == NULL || !initialized) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(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++) {
|
for (int i = 0; i < block_count; i++) {
|
||||||
if (block_list[i].allocated && block_list[i].address == ptr) {
|
if (block_list[i].allocated && block_list[i].address == ptr) {
|
||||||
total_allocated -= block_list[i].size;
|
block_idx = i;
|
||||||
block_list[i].allocated = false;
|
break;
|
||||||
|
|
||||||
// Compact: remove freed entry and shift remaining
|
|
||||||
for (int j = i; j < block_count - 1; j++) {
|
|
||||||
block_list[j] = block_list[j + 1];
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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--;
|
block_count--;
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void* krealloc(void *ptr, size_t new_size) {
|
void* krealloc(void *ptr, size_t new_size) {
|
||||||
if (!initialized) {
|
|
||||||
memory_manager_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_size == 0) {
|
if (new_size == 0) {
|
||||||
kfree(ptr);
|
kfree(ptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -267,24 +275,18 @@ void* krealloc(void *ptr, size_t new_size) {
|
||||||
return kmalloc(new_size);
|
return kmalloc(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the block
|
|
||||||
for (int i = 0; i < block_count; i++) {
|
for (int i = 0; i < block_count; i++) {
|
||||||
if (block_list[i].allocated && block_list[i].address == ptr) {
|
if (block_list[i].allocated && block_list[i].address == ptr) {
|
||||||
if (block_list[i].size >= new_size) {
|
if (block_list[i].size >= new_size) {
|
||||||
// Allocation is large enough
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to allocate new space
|
|
||||||
void *new_ptr = kmalloc(new_size);
|
void *new_ptr = kmalloc(new_size);
|
||||||
if (new_ptr == NULL) {
|
if (new_ptr == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy data
|
|
||||||
mem_memmove(new_ptr, ptr, block_list[i].size);
|
mem_memmove(new_ptr, ptr, block_list[i].size);
|
||||||
|
|
||||||
// Free old pointer
|
|
||||||
kfree(ptr);
|
kfree(ptr);
|
||||||
|
|
||||||
return new_ptr;
|
return new_ptr;
|
||||||
|
|
@ -468,10 +470,7 @@ void memory_reset_peak(void) {
|
||||||
bool memory_is_valid_ptr(void *ptr) {
|
bool memory_is_valid_ptr(void *ptr) {
|
||||||
if (ptr == NULL) return false;
|
if (ptr == NULL) return false;
|
||||||
|
|
||||||
void *pool_start = memory_pool;
|
if (!initialized) {
|
||||||
void *pool_end = (uint8_t *)memory_pool + memory_pool_size;
|
|
||||||
|
|
||||||
if (ptr < pool_start || ptr >= pool_end) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "limine.h"
|
||||||
|
|
||||||
// Memory Manager Configuration
|
// Memory Manager Configuration
|
||||||
#define DEFAULT_POOL_SIZE (128 * 1024 * 1024) // 128MB default
|
#define DEFAULT_POOL_SIZE (128 * 1024 * 1024) // 128MB default
|
||||||
|
|
@ -36,9 +37,7 @@ typedef struct {
|
||||||
} MemStats;
|
} MemStats;
|
||||||
|
|
||||||
// Public API
|
// Public API
|
||||||
void memory_manager_init(void);
|
void memory_manager_init_from_memmap(struct limine_memmap_response *memmap);
|
||||||
void memory_manager_init_with_size(size_t pool_size);
|
|
||||||
void memory_manager_init_at(void *pool_address, size_t pool_size);
|
|
||||||
|
|
||||||
// Allocation/Deallocation
|
// Allocation/Deallocation
|
||||||
void* kmalloc(size_t size);
|
void* kmalloc(size_t size);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue