-
Notifications
You must be signed in to change notification settings - Fork 0
Memory Management
ModuOS implements a three-tier memory management system: physical memory allocation, virtual memory (paging), and kernel heap management.
┌─────────────────────────────────────────────┐
│ 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
File: src/kernel/memory/phys.c
The physical memory allocator manages RAM at 4KB page granularity using a bitmap.
Data Structures:
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 bytesvoid phys_init(uint64_t total_mem,
const void *usable_regions,
size_t region_count);Steps:
- Parse Multiboot2 memory map
- Calculate total pages
- Allocate bitmap (1 bit per 4KB page)
- Mark all memory as used
- 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
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 pagesAlgorithm (First-Fit):
// 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);
}
}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 RAMFile: src/kernel/memory/paging.c
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)
void paging_init(void);Steps:
- Allocate PML4, PDPT, PD tables
- Identity map first 512MB (kernel code/data)
- Set up recursive mapping (optional)
- Load CR3 with PML4 address
- Enable paging (already enabled from boot)
Maps virtual address = physical address for kernel region:
void early_identity_map(void); // Map first 512MB
void early_identity_map_all(void); // Map all available RAMUsage: Kernel can directly access physical addresses without translation during early boot.
// 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);#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)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");
}File: src/kernel/memory/kheap.c
The kernel heap provides malloc-like functionality for kernel code.
API:
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 statisticsImplementation: Simple linked-list allocator
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) │
└──────────────┴─────────────┴──────────────┴─────────────┘
First-Fit Strategy:
- Traverse linked list
- Find first free block ≥ requested size
- Split block if too large
- Mark block as used
- Return pointer to data area (after header)
Free Block Merging:
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;
}
}Currently fixed-size heap. Future versions may expand dynamically:
#define HEAP_INITIAL_SIZE (1 * 1024 * 1024) // 1MB
#define HEAP_MAX_SIZE (16 * 1024 * 1024) // 16MB0x00000000 - 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
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
Ring Levels:
- Ring 0 (Supervisor): Kernel code, full access
- Ring 3 (User): User programs, restricted access
Page Protection:
// Kernel page (Ring 0 only)
flags = PAGE_PRESENT | PAGE_WRITE;
// User page (Ring 3 accessible)
flags = PAGE_PRESENT | PAGE_WRITE | PAGE_USER;Prevent code execution from data pages:
// Data page (no execute)
flags = PAGE_PRESENT | PAGE_WRITE | PAGE_NO_EXECUTE;
// Code page (executable)
flags = PAGE_PRESENT; // No WRITE, no NO_EXECUTEOptimization: Use global pages for kernel
// Mark kernel pages as global (not flushed on CR3 reload)
flags |= PAGE_GLOBAL;2MB Pages: Reduce TLB pressure for large mappings
// Map 2MB page instead of 512 × 4KB pages
pde = phys_addr | PAGE_PRESENT | PAGE_WRITE | PAGE_HUGE;Future optimization: Reduce cache conflicts by aligning allocations
void kheap_stats(void) {
// Print total allocated blocks
// Print total free blocks
// Print fragmentation level
}File: src/kernel/fault.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);
}- Process Management - Per-process memory
- Boot Process - Early paging setup
- Kernel API - Memory functions reference