Better docs and structure
This commit is contained in:
71
memory.c
71
memory.c
@@ -1,5 +1,18 @@
|
||||
/*
|
||||
* memory.c – Kernel memory management.
|
||||
*
|
||||
* Implements three layers:
|
||||
* PMM – bitmap-based physical page-frame allocator backed by a
|
||||
* 16 MB pool obtained from UEFI at boot.
|
||||
* Paging – walks and creates 4-level x86-64 page tables; supports
|
||||
* map, unmap, and virtual-to-physical translation.
|
||||
* Heap – first-fit free-list allocator with block splitting and
|
||||
* bidirectional coalescing; 16-byte aligned.
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
/* Null-safe print helper used throughout the kernel. */
|
||||
#define SAFE_PRINT(Boot, ...) \
|
||||
do { \
|
||||
if ((Boot) != NULL && (Boot)->print != NULL) { \
|
||||
@@ -17,21 +30,36 @@ static UINTN pmm_free_count = 0;
|
||||
static UINT8 pmm_bitmap[PMM_POOL_PAGES / 8];
|
||||
static BOOLEAN pmm_ready = FALSE;
|
||||
|
||||
/* ================================================================
|
||||
* PMM – bitmap helpers
|
||||
* ================================================================ */
|
||||
|
||||
/* Mark page `idx` as allocated. */
|
||||
static void pmm_set_bit(UINTN idx)
|
||||
{
|
||||
pmm_bitmap[idx / 8] |= (UINT8)(1U << (idx % 8));
|
||||
}
|
||||
|
||||
/* Mark page `idx` as free. */
|
||||
static void pmm_clear_bit(UINTN idx)
|
||||
{
|
||||
pmm_bitmap[idx / 8] &= (UINT8)~(1U << (idx % 8));
|
||||
}
|
||||
|
||||
/* Return TRUE if page `idx` is currently allocated. */
|
||||
static BOOLEAN pmm_test_bit(UINTN idx)
|
||||
{
|
||||
return (pmm_bitmap[idx / 8] & (1U << (idx % 8))) != 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* PMM – public interface
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Initialise the PMM: request PMM_POOL_PAGES from UEFI and set up
|
||||
* the bitmap with all pages marked free.
|
||||
*/
|
||||
void pmm_init(BootInfo *Boot)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
@@ -66,6 +94,7 @@ void pmm_init(BootInfo *Boot)
|
||||
pmm_pool_base);
|
||||
}
|
||||
|
||||
/* Allocate a single 4 KB page. Returns physical address or 0. */
|
||||
UINT64 pmm_alloc_page(void)
|
||||
{
|
||||
UINTN i;
|
||||
@@ -85,6 +114,7 @@ UINT64 pmm_alloc_page(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Free a single page previously returned by pmm_alloc_page(). */
|
||||
void pmm_free_page(UINT64 phys_addr)
|
||||
{
|
||||
UINTN idx;
|
||||
@@ -100,6 +130,7 @@ void pmm_free_page(UINT64 phys_addr)
|
||||
pmm_free_count++;
|
||||
}
|
||||
|
||||
/* Allocate `count` physically contiguous pages (first-fit). */
|
||||
UINT64 pmm_alloc_pages(UINTN count)
|
||||
{
|
||||
UINTN i, j;
|
||||
@@ -131,6 +162,7 @@ UINT64 pmm_alloc_pages(UINTN count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Free `count` contiguous pages starting at phys_addr. */
|
||||
void pmm_free_pages(UINT64 phys_addr, UINTN count)
|
||||
{
|
||||
UINTN i;
|
||||
@@ -146,6 +178,11 @@ UINTN pmm_get_total_pages(void) { return pmm_total_pages; }
|
||||
* Paging – manipulate the live 4-level x86-64 page tables
|
||||
* ================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
* Paging – low-level helpers
|
||||
* ================================================================ */
|
||||
|
||||
/* Read the CR3 register (physical address of PML4). */
|
||||
static UINT64 read_cr3(void)
|
||||
{
|
||||
UINT64 cr3;
|
||||
@@ -153,11 +190,13 @@ static UINT64 read_cr3(void)
|
||||
return cr3;
|
||||
}
|
||||
|
||||
/* Invalidate the TLB entry for virtual address `addr`. */
|
||||
static void invlpg(UINT64 addr)
|
||||
{
|
||||
__asm__ __volatile__("invlpg (%0)" :: "r"(addr) : "memory");
|
||||
}
|
||||
|
||||
/* Return a pointer to the current PML4 table. */
|
||||
static UINT64 *get_pml4(void)
|
||||
{
|
||||
return (UINT64 *)(UINTN)(read_cr3() & PTE_ADDR_MASK);
|
||||
@@ -197,12 +236,22 @@ static UINT64 *paging_walk_level(UINT64 *table, UINTN index, BOOLEAN create)
|
||||
return next;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Paging – public interface
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
/* Log the current CR3 value (identity-mapped by UEFI). */
|
||||
void paging_init(BootInfo *Boot)
|
||||
{
|
||||
SAFE_PRINT(Boot, L" Page: CR3 = 0x%lx (UEFI identity-mapped)\n\r",
|
||||
read_cr3());
|
||||
}
|
||||
|
||||
/*
|
||||
* Map a single 4 KB page: virt → phys with the given flags.
|
||||
* Returns TRUE on success, FALSE if a huge page is in the way or
|
||||
* page-table allocation failed.
|
||||
*/
|
||||
BOOLEAN paging_map_page(UINT64 virt, UINT64 phys, UINT64 flags)
|
||||
{
|
||||
UINT64 *pml4, *pdpt, *pd, *pt;
|
||||
@@ -235,6 +284,7 @@ BOOLEAN paging_map_page(UINT64 virt, UINT64 phys, UINT64 flags)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Remove the mapping for a single 4 KB page and flush the TLB. */
|
||||
void paging_unmap_page(UINT64 virt)
|
||||
{
|
||||
UINT64 *pml4, *pdpt, *pd, *pt;
|
||||
@@ -262,6 +312,10 @@ void paging_unmap_page(UINT64 virt)
|
||||
invlpg(virt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a virtual address to its physical counterpart.
|
||||
* Handles 4 KB, 2 MB, and 1 GB page sizes. Returns 0 if unmapped.
|
||||
*/
|
||||
UINT64 paging_get_phys(UINT64 virt)
|
||||
{
|
||||
UINT64 *pml4, *pdpt, *pd, *pt;
|
||||
@@ -302,11 +356,16 @@ UINT64 paging_get_phys(UINT64 virt)
|
||||
static HeapBlock *heap_start = NULL;
|
||||
static BOOLEAN heap_ready = FALSE;
|
||||
|
||||
/* Round `val` up to the next multiple of `align`. */
|
||||
static UINTN align_up(UINTN val, UINTN align)
|
||||
{
|
||||
return (val + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the heap: allocate HEAP_INITIAL_PAGES from the PMM
|
||||
* and set up a single free block spanning the entire region.
|
||||
*/
|
||||
void heap_init(BootInfo *Boot)
|
||||
{
|
||||
UINT64 phys;
|
||||
@@ -333,6 +392,11 @@ void heap_init(BootInfo *Boot)
|
||||
heap_size / 1024, phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate `size` bytes from the heap (first-fit).
|
||||
* The returned pointer is aligned to HEAP_ALIGN. Returns NULL on
|
||||
* failure or heap corruption.
|
||||
*/
|
||||
void *kmalloc(UINTN size)
|
||||
{
|
||||
HeapBlock *block, *split;
|
||||
@@ -377,6 +441,10 @@ void *kmalloc(UINTN size)
|
||||
return NULL; /* out of heap memory */
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a previously kmalloc'd pointer. Coalesces adjacent free
|
||||
* blocks to reduce fragmentation.
|
||||
*/
|
||||
void kfree(void *ptr)
|
||||
{
|
||||
HeapBlock *block;
|
||||
@@ -416,6 +484,7 @@ void kfree(void *ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Gather aggregate heap statistics. */
|
||||
void heap_get_stats(UINTN *total, UINTN *used, UINTN *free_mem,
|
||||
UINTN *num_blocks)
|
||||
{
|
||||
@@ -441,6 +510,7 @@ void heap_get_stats(UINTN *total, UINTN *used, UINTN *free_mem,
|
||||
* Top-level helpers
|
||||
* ================================================================ */
|
||||
|
||||
/* Initialise all memory subsystems in order. */
|
||||
void memory_init(BootInfo *Boot)
|
||||
{
|
||||
SAFE_PRINT(Boot, L"Initializing memory management...\n\r");
|
||||
@@ -450,6 +520,7 @@ void memory_init(BootInfo *Boot)
|
||||
SAFE_PRINT(Boot, L"Memory management ready.\n\r\n\r");
|
||||
}
|
||||
|
||||
/* Print a summary of PMM, heap, and paging state to the console. */
|
||||
void memory_print_stats(BootInfo *Boot)
|
||||
{
|
||||
UINTN h_total, h_used, h_free, h_blocks;
|
||||
|
||||
Reference in New Issue
Block a user