Upload files to "lib/mm"

This commit is contained in:
2025-05-20 20:45:34 -05:00
parent 9963907545
commit 7fee654d7c
3 changed files with 297 additions and 0 deletions

136
lib/mm/heap.c Normal file
View File

@ -0,0 +1,136 @@
#include <stdio.h>
#include <string.h>
#include <mm/heap.h>
#include <mm/pmm.h>
#include <mm/paging.h>
#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;
}
}

82
lib/mm/paging.c Normal file
View File

@ -0,0 +1,82 @@
#include <string.h>
#include <stdio.h>
#include <mm/paging.h>
#include <mm/pmm.h>
#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 (04MB) */
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");
}

79
lib/mm/pmm.c Normal file
View File

@ -0,0 +1,79 @@
#include <stddef.h>
#include <mm/pmm.h>
#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);
}