From 7fee654d7cb94462ce724f25ee4c6fed5bd28325 Mon Sep 17 00:00:00 2001 From: david-on-debian Date: Tue, 20 May 2025 20:45:34 -0500 Subject: [PATCH] Upload files to "lib/mm" --- lib/mm/heap.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/mm/paging.c | 82 +++++++++++++++++++++++++++++ lib/mm/pmm.c | 79 ++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 lib/mm/heap.c create mode 100644 lib/mm/paging.c create mode 100644 lib/mm/pmm.c diff --git a/lib/mm/heap.c b/lib/mm/heap.c new file mode 100644 index 0000000..28fc841 --- /dev/null +++ b/lib/mm/heap.c @@ -0,0 +1,136 @@ +#include +#include + +#include +#include +#include + + +#define ALIGNMENT 8 +#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1)) + +typedef struct block_header { + size_t size; + struct block_header* next; + int free; +} block_header_t; + +#define BLOCK_SIZE sizeof(block_header_t) + +static uint8_t* heap_base = (uint8_t*)HEAP_START; +static uint8_t* heap_end = (uint8_t*)(HEAP_START + HEAP_SIZE); + +static block_header_t* free_list = NULL; + + +void heap_init(void) +{ + free_list = (block_header_t*)heap_base; + free_list->size = HEAP_SIZE - BLOCK_SIZE; + free_list->next = NULL; + free_list->free = 1; +} + + +void* malloc(size_t size) +{ + size = ALIGN(size); + block_header_t* curr = free_list; + + while (curr) + { + if (curr->free && curr->size >= size) + { + /* Split if there's space for another block */ + if (curr->size >= size + BLOCK_SIZE + ALIGNMENT) + { + block_header_t* new_block = (block_header_t*)((uint8_t*)curr + BLOCK_SIZE + size); + new_block->size = curr->size - size - BLOCK_SIZE; + new_block->next = curr->next; + new_block->free = 1; + + curr->next = new_block; + curr->size = size; + } + + curr->free = 0; + return (void*)((uint8_t*)curr + BLOCK_SIZE); + } + curr = curr->next; + } + + printd("Malloc failed due to lack of free memory\n"); + return NULL; +} + +void* calloc(size_t nmemb, size_t size) +{ + size_t total = nmemb * size; + void* ptr = malloc(total); + if (ptr) + { + memset(ptr, 0, total); + } + return ptr; +} + +void* realloc(void* ptr, size_t size) +{ + if (!ptr) + { + return malloc(size); + } + + if (size == 0) + { + free(ptr); + return NULL; + } + + block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE); + if (block->size >= size) + { + return ptr; + } + + void* new_ptr = malloc(size); + if (new_ptr) { + memcpy(new_ptr, ptr, block->size); + free(ptr); + } + return new_ptr; +} + +void free(void* ptr) +{ + if (!ptr) + { + return; + } + + block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE); + block->free = 1; + + /* Forward coalescing */ + if (block->next && block->next->free) + { + block->size += BLOCK_SIZE + block->next->size; + block->next = block->next->next; + } + + /* Backward coalescing */ + block_header_t* prev = NULL; + block_header_t* curr = free_list; + + while (curr && curr != block) + { + prev = curr; + curr = curr->next; + } + + if (prev && prev->free) + { + prev->size += BLOCK_SIZE + block->size; + prev->next = block->next; + } +} diff --git a/lib/mm/paging.c b/lib/mm/paging.c new file mode 100644 index 0000000..6b06e5b --- /dev/null +++ b/lib/mm/paging.c @@ -0,0 +1,82 @@ +#include +#include + +#include +#include + +#define PAGE_DIRECTORY_ENTRIES 1024 +#define PAGE_TABLE_ENTRIES 1024 +#define PAGE_SIZE 4096 + +typedef uint32_t page_directory_entry_t; +typedef uint32_t page_table_entry_t; + +static page_directory_entry_t* page_directory = (page_directory_entry_t*)0x9C000; /* Must be page-aligned */ +static page_table_entry_t* page_tables[PAGE_DIRECTORY_ENTRIES]; + +extern void _enable_paging_asm(void); + +void paging_init(void) +{ + /* Allocate and clear the page directory */ + page_directory = (uint32_t*)alloc_page(); + memset(page_directory, 0, 4096); + + /* Allocate and set up the first identity-mapped page table (0–4MB) */ + uint32_t* first_table = (uint32_t*)alloc_page(); + memset(first_table, 0, 4096); + for (uint32_t i = 0; i < 1024; i++) + { + first_table[i] = (i * 0x1000) | 3; /* Present | RW */ + } + page_directory[0] = ((uint32_t)first_table) | 3; + + /* --- Map 4MB heap at 0xC0000000 --- */ + uint32_t* heap_table = (uint32_t*)alloc_page(); + memset(heap_table, 0, 4096); + + for (uint32_t i = 0; i < 1024; i++) /* 256 pages = 1MB */ + { + uint32_t phys = (uint32_t)alloc_page(); + if (phys == 0) + { + printf("Out of physical memory during heap mapping!\n"); + while (1); + } + heap_table[i] = phys | 3; /* Present | RW */ + } + + /* 0xC0000000 >> 22 == 768 */ + page_directory[768] = ((uint32_t)heap_table) | 3; + + // Load page directory + asm volatile ("mov %0, %%cr3" : : "r"(page_directory)); + + /* Enable paging */ + _enable_paging_asm(); +} + +void map_page(void* phys_addr, void* virt_addr) +{ + uint32_t pd_index = ((uint32_t)virt_addr >> 22) & 0x3FF; + uint32_t pt_index = ((uint32_t)virt_addr >> 12) & 0x3FF; + + /* Allocate page table if necessary */ + if (!(page_directory[pd_index] & 1)) + { + void* pt_phys = alloc_page(); + page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */ + + for (int i = 0; i < PAGE_TABLE_ENTRIES; i++) + { + page_tables[pd_index][i] = 0x00000002; /* Not present */ + } + + page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */ + } + + page_table_entry_t* page_table = (page_table_entry_t*)((page_directory[pd_index] & 0xFFFFF000) | 0xC0000000); + page_table[pt_index] = ((uint32_t)phys_addr & 0xFFFFF000) | 0x3; /* Present, R/W */ + + asm volatile ("invlpg (%0)" :: "r" (virt_addr) : "memory"); +} diff --git a/lib/mm/pmm.c b/lib/mm/pmm.c new file mode 100644 index 0000000..637780c --- /dev/null +++ b/lib/mm/pmm.c @@ -0,0 +1,79 @@ +#include + +#include + +#define PAGE_SIZE 4096 +#define BITMAP_SIZE (1024 * 1024) /* Supports up to 4GB RAM (1 bit per page) */ + +static uint8_t bitmap[BITMAP_SIZE / 8]; +static uint32_t total_pages; +static uint32_t used_pages = 0; + +static inline void set_bit(uint32_t idx) +{ + bitmap[idx / 8] |= (1 << (idx % 8)); +} + +static inline void clear_bit(uint32_t idx) +{ + bitmap[idx / 8] &= ~(1 << (idx % 8)); +} + +static inline int test_bit(uint32_t idx) +{ + return (bitmap[idx / 8] >> (idx % 8)) & 1; +} + +void pmm_init(multiboot_info_t* mb_info) +{ + total_pages = 0x100000; /* 4GB / 4KB = 1M pages */ + for (uint32_t i = 0; i < total_pages / 8; i++) + { + bitmap[i] = 0xFF; /* Mark all as used */ + } + + multiboot_memory_map_t* mmap = (multiboot_memory_map_t*) mb_info->mmap_addr; + while ((uint32_t)mmap < mb_info->mmap_addr + mb_info->mmap_length) + { + if (mmap->type == 1) /* Usable */ + { + uint64_t base = mmap->addr; + uint64_t len = mmap->len; + for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE) + { + if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */ + { + uint32_t idx = addr / PAGE_SIZE; + + if (idx >= total_pages) + { + continue; /* skip entries above 4GB */ + } + + clear_bit(idx); + used_pages--; + } + } + } + mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size)); + } +} + +void* alloc_page(void) { + for (uint32_t i = 0; i < total_pages; i++) + { + if (!test_bit(i)) + { + set_bit(i); + used_pages++; + return (void*)(i * PAGE_SIZE); + } + } + return NULL; /* Out of memory */ +} + +void free_page(void* ptr) +{ + uint32_t idx = (uint32_t)ptr / PAGE_SIZE; + clear_bit(idx); +}