diff --git a/src/mem/memory_manager.c b/src/mem/memory_manager.c index d8dfb82..be4ff2b 100644 --- a/src/mem/memory_manager.c +++ b/src/mem/memory_manager.c @@ -44,6 +44,7 @@ static MemBlock *block_list = _bootstrap_blocks; static int block_capacity = BLOCK_LIST_INITIAL_CAPACITY; static int block_count = 0; static bool on_heap = false; +static bool growing = false; static size_t memory_pool_size = 0; static size_t total_allocated = 0; @@ -90,8 +91,12 @@ static uint32_t get_timestamp(void) { } static bool insert_block_at(int idx, void *addr, size_t size, bool allocated, uint32_t id) { - if (block_count >= block_capacity && !grow_block_list()) - return false; + // Proactive growth: If we're within 10 slots of full, grow the list now. + // This ensures we always have metadata space to split blocks even during a nested kmalloc. + if (block_count >= block_capacity - 10 && !growing) { + grow_block_list(); + } + if (block_count >= block_capacity) return false; for (int j = block_count; j > idx; j--) block_list[j] = block_list[j - 1]; block_list[idx] = (MemBlock){ @@ -192,7 +197,6 @@ static void _kfree_locked(void *ptr) { // _kmalloc_locked can call grow_block_list again if the block list fills // during the allocation of the new array, causing infinite recursion without this flag. static bool grow_block_list(void) { - static bool growing = false; if (growing) return false; growing = true; @@ -200,12 +204,17 @@ static bool grow_block_list(void) { MemBlock *nl = (MemBlock *)_kmalloc_locked((size_t)new_cap * sizeof(MemBlock), 8); if (!nl) { growing = false; return false; } - if (on_heap) _kfree_locked(block_list); mem_memcpy(nl, block_list, (size_t)block_count * sizeof(MemBlock)); + + MemBlock *old_ptr = block_list; + bool old_on_heap = on_heap; + block_list = nl; block_capacity = new_cap; on_heap = true; growing = false; + + if (old_on_heap) _kfree_locked(old_ptr); return true; } @@ -350,8 +359,20 @@ static void *slab_alloc(int cls) { serial_write(" page="); k_itoa_hex((uint64_t)page, b); serial_write(b); serial_write(" fl="); k_itoa_hex((uint64_t)obj, b); serial_write(b); serial_write("\n"); + + // Remove the corrupted page from the list to avoid hitting it again + if (cache->pages == page) { + cache->pages = page->next; + } else { + SlabPage *prev = cache->pages; + while (prev && prev->next != page) prev = prev->next; + if (prev) prev->next = page->next; + } + page->free_count = 0; page->freelist = NULL; + page->next = NULL; // Isolate it + page = slab_new_page(cls); if (!page) return NULL; page->next = cache->pages; @@ -452,6 +473,15 @@ void *kmalloc(size_t size) { return kmalloc_aligned(size, 8); } +// kcalloc ensures memory is zeroed, which is critical for many kernel and library +// structures (like lwIP PCBs) that assume a null-initialized state. +void *kcalloc(size_t n, size_t size) { + size_t total = n * size; + void *ptr = kmalloc(total); + if (ptr) mem_memset(ptr, 0, total); + return ptr; +} + void kfree(void *ptr) { if (!ptr || !initialized) return; uint64_t rflags = spinlock_acquire_irqsave(&mm_lock); diff --git a/src/mem/memory_manager.h b/src/mem/memory_manager.h index 43bface..3a8c050 100644 --- a/src/mem/memory_manager.h +++ b/src/mem/memory_manager.h @@ -11,7 +11,7 @@ // SLAB_CLASSES and SLAB_MAX_SIZE must stay in sync with the slab_sizes[] table in memory_manager.c. #define DEFAULT_POOL_SIZE (128 * 1024 * 1024) -#define BLOCK_LIST_INITIAL_CAPACITY 64 +#define BLOCK_LIST_INITIAL_CAPACITY 1024 #define SLAB_CLASSES 7 #define SLAB_MAX_SIZE 512 @@ -44,6 +44,7 @@ typedef struct { void memory_manager_init_from_memmap(struct limine_memmap_response *memmap); void* kmalloc(size_t size); +void* kcalloc(size_t n, size_t size); // alignment must be a power of 2. Requests <= 512 B with alignment <= 8 are served by the slab allocator. void* kmalloc_aligned(size_t size, size_t alignment); void kfree(void *ptr); diff --git a/src/mem/paging.c b/src/mem/paging.c index 81a4c39..7f40b81 100644 --- a/src/mem/paging.c +++ b/src/mem/paging.c @@ -135,9 +135,6 @@ void paging_destroy_user_pml4_phys(uint64_t pml4_phys) { for (int pt_idx = 0; pt_idx < 512; pt_idx++) { if (pt->entries[pt_idx] & PT_PRESENT) { - uint64_t phys_addr = pt->entries[pt_idx] & PT_ADDR_MASK; - extern void kfree(void* ptr); - kfree((void*)p2v(phys_addr)); } } extern void kfree(void* ptr); diff --git a/src/mem/paging.h b/src/mem/paging.h index 4b34a34..9a4c478 100644 --- a/src/mem/paging.h +++ b/src/mem/paging.h @@ -35,6 +35,7 @@ uint64_t paging_create_user_pml4_phys(void); void paging_switch_directory(uint64_t pml4_phys); +// Destroys a user page directory, reclaiming all physical memory used for page table structures. void paging_destroy_user_pml4_phys(uint64_t pml4_phys); void paging_init(void);