# Memory Management ModuOS implements a three-tier memory management system: physical memory allocation, virtual memory (paging), and kernel heap management. ## Overview ``` ┌─────────────────────────────────────────────┐ │ Kernel Heap (kmalloc/kfree) │ │ kheap.c │ └──────────────────┬──────────────────────────┘ │ ┌──────────────────▼──────────────────────────┐ │ Virtual Memory (Paging) │ │ 4-Level Page Tables (PML4) │ │ paging.c │ └──────────────────┬──────────────────────────┘ │ ┌──────────────────▼──────────────────────────┐ │ Physical Memory Allocator │ │ Bitmap-based Page Allocator │ │ phys.c │ └──────────────────┬──────────────────────────┘ │ Physical RAM ``` ## Physical Memory Management **File**: `src/kernel/memory/phys.c` ### Architecture The physical memory allocator manages RAM at **4KB page granularity** using a bitmap. **Data Structures**: ```c static uint64_t *phys_bitmap = NULL; // Bitmap: 1 bit per page static uint64_t phys_total_pages = 0; // Total pages in system static uint64_t phys_used_pages = 0; // Currently allocated pages static uint64_t phys_total_memory = 0; // Total memory in bytes ``` ### Initialization ```c void phys_init(uint64_t total_mem, const void *usable_regions, size_t region_count); ``` **Steps**: 1. Parse Multiboot2 memory map 2. Calculate total pages 3. Allocate bitmap (1 bit per 4KB page) 4. Mark all memory as used 5. Mark usable regions as free **Memory Map Types** (from Multiboot2): - `MULTIBOOT_MEMORY_AVAILABLE` (1): Usable RAM - `MULTIBOOT_MEMORY_RESERVED` (2): Reserved by BIOS - `MULTIBOOT_MEMORY_ACPI_RECLAIMABLE` (3): ACPI tables - `MULTIBOOT_MEMORY_NVS` (4): Non-volatile storage - `MULTIBOOT_MEMORY_BADRAM` (5): Defective RAM ### Page Allocation ```c void* phys_alloc_page(void); // Allocate single 4KB page void* phys_alloc_pages(size_t n); // Allocate n contiguous pages void phys_free_page(void* addr); // Free single page void phys_free_pages(void* addr, size_t n); // Free n pages ``` **Algorithm** (First-Fit): ```c // Find first free page for (uint64_t i = 0; i < phys_total_pages; i++) { uint64_t bitmap_index = i / 64; uint64_t bit_index = i % 64; if (!(phys_bitmap[bitmap_index] & (1ULL << bit_index))) { // Page is free phys_bitmap[bitmap_index] |= (1ULL << bit_index); // Mark used return (void*)(i * PAGE_SIZE); } } ``` ### Memory Statistics ```c uint64_t phys_get_total_memory(void); // Total RAM uint64_t phys_get_used_memory(void); // Used RAM uint64_t phys_get_free_memory(void); // Available RAM ``` ## Virtual Memory (Paging) **File**: `src/kernel/memory/paging.c` ### 4-Level Paging Structure ModuOS uses the **x86-64 4-level paging** hierarchy: ``` Virtual Address (48-bit): ┌──────┬──────┬──────┬──────┬──────────────┐ │ PML4 │ PDPT │ PD │ PT │ Offset │ │ 9bit │ 9bit │ 9bit │ 9bit │ 12bit │ └──────┴──────┴──────┴──────┴──────────────┘ 47:39 38:30 29:21 20:12 11:0 PML4 Entry → PDPT (512 entries × 512GB = 256TB) PDPT Entry → PD (512 entries × 1GB) PD Entry → PT (512 entries × 2MB) PT Entry → Page (512 entries × 4KB) ``` **Entry Format** (64-bit): ``` Bit 0: Present (P) Bit 1: Read/Write (R/W) Bit 2: User/Supervisor (U/S) Bit 3: Page-level Write-Through (PWT) Bit 4: Page-level Cache Disable (PCD) Bit 5: Accessed (A) Bit 6: Dirty (D) Bit 7: Page Size (PS) - 1=2MB/1GB page Bit 8: Global (G) Bits 9-11: Available for OS Bits 12-51: Physical address (4KB aligned) Bit 63: Execute Disable (XD/NX) ``` ### Initialization ```c void paging_init(void); ``` **Steps**: 1. Allocate PML4, PDPT, PD tables 2. Identity map first 512MB (kernel code/data) 3. Set up recursive mapping (optional) 4. Load CR3 with PML4 address 5. Enable paging (already enabled from boot) ### Identity Mapping Maps virtual address = physical address for kernel region: ```c void early_identity_map(void); // Map first 512MB void early_identity_map_all(void); // Map all available RAM ``` **Usage**: Kernel can directly access physical addresses without translation during early boot. ### Page Table Operations ```c // Map virtual address to physical frame int paging_map_page(uint64_t virt_addr, uint64_t phys_addr, uint64_t flags); // Unmap virtual address void paging_unmap_page(uint64_t virt_addr); // Get physical address from virtual uint64_t paging_get_physical(uint64_t virt_addr); // Create new page directory uint64_t* paging_create_directory(void); // Switch page directory void paging_switch_directory(uint64_t* pml4); ``` ### Page Flags ```c #define PAGE_PRESENT (1 << 0) #define PAGE_WRITE (1 << 1) #define PAGE_USER (1 << 2) #define PAGE_WRITETHROUGH (1 << 3) #define PAGE_CACHE_DISABLE (1 << 4) #define PAGE_ACCESSED (1 << 5) #define PAGE_DIRTY (1 << 6) #define PAGE_HUGE (1 << 7) // 2MB or 1GB page #define PAGE_GLOBAL (1 << 8) #define PAGE_NO_EXECUTE (1ULL << 63) ``` ### TLB Management ```c static inline void tlb_flush_all(void) { uint64_t cr3; __asm__ volatile("mov %%cr3, %0" : "=r"(cr3)); __asm__ volatile("mov %0, %%cr3" : : "r"(cr3) : "memory"); } static inline void tlb_flush_page(uint64_t virt_addr) { __asm__ volatile("invlpg (%0)" : : "r"(virt_addr) : "memory"); } ``` ## Kernel Heap **File**: `src/kernel/memory/kheap.c` ### Dynamic Memory Allocation The kernel heap provides `malloc`-like functionality for kernel code. **API**: ```c void* kmalloc(size_t size); // Allocate memory void* kmalloc_aligned(size_t size, size_t alignment); // Aligned allocation void* kzalloc(size_t size); // Zero-initialized allocation void kfree(void* ptr); // Free memory void kheap_stats(void); // Print heap statistics ``` ### Heap Structure **Implementation**: Simple linked-list allocator ```c typedef struct heap_block { size_t size; // Block size (excluding header) int used; // 1 if allocated, 0 if free struct heap_block *next; // Next block in list } heap_block_t; ``` **Memory Layout**: ``` Heap Start ↓ ┌──────────────┬─────────────┬──────────────┬─────────────┐ │ Block Header │ Data │ Block Header │ Data │ ... │ used=1 │ (alloc) │ used=0 │ (free) │ └──────────────┴─────────────┴──────────────┴─────────────┘ ``` ### Allocation Algorithm **First-Fit Strategy**: 1. Traverse linked list 2. Find first free block ≥ requested size 3. Split block if too large 4. Mark block as used 5. Return pointer to data area (after header) ### Coalescing **Free Block Merging**: ```c void kfree(void* ptr) { // Mark block as free block->used = 0; // Merge with next block if free if (block->next && !block->next->used) { block->size += sizeof(heap_block_t) + block->next->size; block->next = block->next->next; } } ``` ### Heap Growth Currently **fixed-size heap**. Future versions may expand dynamically: ```c #define HEAP_INITIAL_SIZE (1 * 1024 * 1024) // 1MB #define HEAP_MAX_SIZE (16 * 1024 * 1024) // 16MB ``` ## Memory Layout ### Physical Memory Map ``` 0x00000000 - 0x000FFFFF : Real Mode region (1MB) 0x00000000 - 0x000003FF : Real Mode IVT 0x00000400 - 0x000004FF : BIOS Data Area 0x00000500 - 0x00007BFF : Free conventional memory 0x00007C00 - 0x00007DFF : Boot sector (GRUB) 0x00007E00 - 0x0009FFFF : Free conventional memory 0x000A0000 - 0x000BFFFF : Video memory 0x000C0000 - 0x000FFFFF : BIOS ROM 0x00100000 - 0x???????? : Kernel (loaded by GRUB) 0x???????? - 0x???????? : Kernel heap 0x???????? - 0x???????? : Available RAM ``` ### Virtual Memory Layout **Current (Identity Mapped)**: ``` 0x00000000 - 0x1FFFFFFF : Identity mapped (512MB) 0x00100000 - 0x00?????? : Kernel code/data 0x00?????? - 0x00?????? : Kernel heap 0x00?????? - 0x1FFFFFFF : Available 0xFFFFFFFF80000000 - ... : Higher-half kernel (future) ``` **Future (Higher-Half Kernel)**: ``` 0x00000000 - 0x00007FFFFFFFFFFF : User space (128TB) 0x0000800000000000 - 0xFFFF7FFFFFFFFFFF : Non-canonical (unusable) 0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF : Kernel space (128TB) 0xFFFFFFFF80000000 - 0xFFFFFFFFFFFFFFFF : Kernel code/data 0xFFFFFFFFC0000000 - 0xFFFFFFFFFFFFFFFF : Kernel heap ``` ## Memory Protection ### Kernel vs. User Space **Ring Levels**: - **Ring 0** (Supervisor): Kernel code, full access - **Ring 3** (User): User programs, restricted access **Page Protection**: ```c // Kernel page (Ring 0 only) flags = PAGE_PRESENT | PAGE_WRITE; // User page (Ring 3 accessible) flags = PAGE_PRESENT | PAGE_WRITE | PAGE_USER; ``` ### No Execute (NX) Prevent code execution from data pages: ```c // Data page (no execute) flags = PAGE_PRESENT | PAGE_WRITE | PAGE_NO_EXECUTE; // Code page (executable) flags = PAGE_PRESENT; // No WRITE, no NO_EXECUTE ``` ## Performance Considerations ### TLB (Translation Lookaside Buffer) **Optimization**: Use global pages for kernel ```c // Mark kernel pages as global (not flushed on CR3 reload) flags |= PAGE_GLOBAL; ``` ### Huge Pages **2MB Pages**: Reduce TLB pressure for large mappings ```c // Map 2MB page instead of 512 × 4KB pages pde = phys_addr | PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE; ``` ### Page Coloring **Future optimization**: Reduce cache conflicts by aligning allocations ## Debugging ### Memory Leak Detection ```c void kheap_stats(void) { // Print total allocated blocks // Print total free blocks // Print fragmentation level } ``` ### Page Fault Handler **File**: `src/kernel/fault.c` ```c void page_fault_handler(registers_t *regs) { uint64_t faulting_address; __asm__ volatile("mov %%cr2, %0" : "=r"(faulting_address)); uint64_t error_code = regs->err_code; // Parse error code int present = !(error_code & 0x1); int write = error_code & 0x2; int user = error_code & 0x4; int reserved = error_code & 0x8; int instruction = error_code & 0x10; panic("Page Fault at 0x%llx", faulting_address); } ``` ## Next Steps - [Process Management](Process-Management.md) - Per-process memory - [Boot Process](Boot-Process.md) - Early paging setup - [Kernel API](Kernel-API.md) - Memory functions reference