diff --git a/Makefile b/Makefile index 19b87f9..5c166a3 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/boredos.iso b/boredos.iso index 2d5fc5c..d180931 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/build/cmd.o b/build/cmd.o index 7269daf..d5ff733 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/disk_manager.o b/build/disk_manager.o index 86f9aa3..58bbcaa 100644 Binary files a/build/disk_manager.o and b/build/disk_manager.o differ diff --git a/build/dns.o b/build/dns.o index f1c7a43..9ab0bd9 100644 Binary files a/build/dns.o and b/build/dns.o differ diff --git a/build/explorer.o b/build/explorer.o index 77b3f76..0a51153 100644 Binary files a/build/explorer.o and b/build/explorer.o differ diff --git a/build/fat32.o b/build/fat32.o index 0b56278..23eb667 100644 Binary files a/build/fat32.o and b/build/fat32.o differ diff --git a/build/icmp.o b/build/icmp.o index 8f96481..19dd007 100644 Binary files a/build/icmp.o and b/build/icmp.o differ diff --git a/build/main.o b/build/main.o index c3e246a..db5e58b 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/memory_manager.o b/build/memory_manager.o index 39d00ca..9546f20 100644 Binary files a/build/memory_manager.o and b/build/memory_manager.o differ diff --git a/build/nj_kernel.o b/build/nj_kernel.o index 40963f2..10cbc5e 100644 Binary files a/build/nj_kernel.o and b/build/nj_kernel.o differ diff --git a/src/kernel/.DS_Store b/src/kernel/.DS_Store index 5a47950..5d13e94 100644 Binary files a/src/kernel/.DS_Store and b/src/kernel/.DS_Store differ diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index 9e2639b..07a0cb1 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -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; diff --git a/src/kernel/dns.c b/src/kernel/dns.c index a64a1e0..67f24e3 100644 --- a/src/kernel/dns.c +++ b/src/kernel/dns.c @@ -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]; diff --git a/src/kernel/main.c b/src/kernel/main.c index 93b507b..4f6a1f7 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -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) { diff --git a/src/kernel/man_entries.h b/src/kernel/man_entries.h index 324e929..72f53f2 100644 --- a/src/kernel/man_entries.h +++ b/src/kernel/man_entries.h @@ -53,7 +53,7 @@ void create_man_entries(void) { write_man_file("mv", "MV - Move or rename file\n\nUsage: mv \n\nMoves or renames a file or directory."); write_man_file("cp", "CP - Copy file\n\nUsage: cp \n\nCopies a file from the source path to the destination path."); write_man_file("touch", "TOUCH - Create empty file\n\nUsage: touch \n\nCreates a new empty file if it doesn't exist."); - write_man_file("cc", "CC - C Compiler\n\nUsage: cc \n\nThe BoredOS C Compiler. Compiles C source files into ELF executables."); + write_man_file("cc", "CC - C Compiler\n\nUsage: cc \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."); diff --git a/src/kernel/memory_manager.c b/src/kernel/memory_manager.c index 6c03f83..6ade422 100644 --- a/src/kernel/memory_manager.c +++ b/src/kernel/memory_manager.c @@ -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 +#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; } diff --git a/src/kernel/memory_manager.h b/src/kernel/memory_manager.h index 7ba01fd..91e557d 100644 --- a/src/kernel/memory_manager.h +++ b/src/kernel/memory_manager.h @@ -7,6 +7,7 @@ #include #include #include +#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);