Espresso 0.0.2a
This commit is contained in:
190
lib/mm/heap.c
190
lib/mm/heap.c
@ -1,76 +1,138 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <mm/heap.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/paging.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <mm_macros.h>
|
||||
|
||||
#include <mm/heap.h>
|
||||
|
||||
#define ALIGNMENT 8
|
||||
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
|
||||
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||
#define MIN_BLOCK_SIZE 16
|
||||
|
||||
typedef struct block_header {
|
||||
typedef struct block {
|
||||
size_t size;
|
||||
struct block_header* next;
|
||||
struct block* next;
|
||||
int free;
|
||||
} block_header_t;
|
||||
} block_t;
|
||||
|
||||
#define BLOCK_SIZE sizeof(block_header_t)
|
||||
#define BLOCK_SIZE sizeof(block_t)
|
||||
|
||||
static uint8_t* heap_base = (uint8_t*)HEAP_START;
|
||||
static uint8_t* heap_end = (uint8_t*)(HEAP_START + HEAP_SIZE);
|
||||
static uint8_t* heap_base;
|
||||
static uint8_t* heap_end;
|
||||
static size_t heap_size;
|
||||
static block_t* free_list;
|
||||
|
||||
static block_header_t* free_list = NULL;
|
||||
|
||||
|
||||
void heap_init(void)
|
||||
void heap_init(uint32_t start, uint32_t size)
|
||||
{
|
||||
free_list = (block_header_t*)heap_base;
|
||||
free_list->size = HEAP_SIZE - BLOCK_SIZE;
|
||||
free_list->next = NULL;
|
||||
#ifdef _DEBUG
|
||||
printf("[ HEAP ] Initializing heap allocator...\n");
|
||||
#endif
|
||||
|
||||
heap_base = (uint8_t*) ALIGN4((uintptr_t) start);
|
||||
heap_end = heap_base;
|
||||
heap_size = size;
|
||||
free_list = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < size; i += 0x1000)
|
||||
{
|
||||
map_page(pmm_alloc_page(), (void*)(start + i));
|
||||
}
|
||||
|
||||
/* Set up initial free block */
|
||||
free_list = (block_t*)heap_base;
|
||||
free_list->size = heap_size - BLOCK_SIZE;
|
||||
free_list->free = 1;
|
||||
free_list->next = NULL;
|
||||
|
||||
heap_end = heap_base + size;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ HEAP ] Heap allocator initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* malloc(size_t size)
|
||||
static block_t* find_free_block(size_t size)
|
||||
{
|
||||
size = ALIGN(size);
|
||||
block_header_t* curr = free_list;
|
||||
|
||||
block_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);
|
||||
return curr;
|
||||
}
|
||||
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
printd("Malloc failed due to lack of free memory\n");
|
||||
|
||||
printf("find_free_block(): No free block found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void split_block(block_t* blk, size_t size)
|
||||
{
|
||||
if (blk->size >= size + BLOCK_SIZE + MIN_BLOCK_SIZE)
|
||||
{
|
||||
block_t* new_blk = (block_t*)((uint8_t*)blk + BLOCK_SIZE + size);
|
||||
new_blk->size = blk->size - size - BLOCK_SIZE;
|
||||
new_blk->free = 1;
|
||||
new_blk->next = blk->next;
|
||||
blk->next = new_blk;
|
||||
blk->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
void* malloc(size_t size)
|
||||
{
|
||||
size = ALIGN4(size);
|
||||
block_t* blk = find_free_block(size);
|
||||
|
||||
if (!blk)
|
||||
{
|
||||
printf("malloc(): No free block found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
split_block(blk, size);
|
||||
blk->free = 0;
|
||||
return (void*)((uint8_t*)blk + BLOCK_SIZE);
|
||||
}
|
||||
|
||||
void free(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
blk->free = 1;
|
||||
|
||||
/* coalesce */
|
||||
block_t* curr = free_list;
|
||||
while (curr && curr->next)
|
||||
{
|
||||
if (curr->free && curr->next->free)
|
||||
{
|
||||
curr->size += BLOCK_SIZE + curr->next->size;
|
||||
curr->next = curr->next->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t total = nmemb * size;
|
||||
void* ptr = malloc(total);
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
memset(ptr, 0, total);
|
||||
MEMSET(ptr, 0, total);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -81,57 +143,25 @@ void* realloc(void* ptr, size_t size)
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
if (!size)
|
||||
{
|
||||
free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block_header_t* block = (block_header_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
if (block->size >= size)
|
||||
block_t* blk = (block_t*)((uint8_t*)ptr - BLOCK_SIZE);
|
||||
if (blk->size >= size)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* new_ptr = malloc(size);
|
||||
if (new_ptr) {
|
||||
memcpy(new_ptr, ptr, block->size);
|
||||
|
||||
if (new_ptr)
|
||||
{
|
||||
memcpy(new_ptr, ptr, blk->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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
110
lib/mm/paging.c
110
lib/mm/paging.c
@ -1,82 +1,60 @@
|
||||
#include <mm/pmm.h>
|
||||
#include <string.h>
|
||||
#include <mm_macros.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mm/paging.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <mm/heap.h>
|
||||
|
||||
#define PAGE_DIRECTORY_ENTRIES 1024
|
||||
#define PAGE_TABLE_ENTRIES 1024
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_PRESENT 0x1
|
||||
#define PAGE_WRITE 0x2
|
||||
#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 = NULL; /* Will be allocated */
|
||||
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 = (page_directory_entry_t*)alloc_page();
|
||||
memset(page_directory, 0, PAGE_SIZE);
|
||||
|
||||
/* Allocate and set up the first identity-mapped page table (0-4MB) */
|
||||
page_tables[0] = (page_table_entry_t*)alloc_page();
|
||||
memset(page_tables[0], 0, PAGE_SIZE);
|
||||
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++)
|
||||
{
|
||||
page_tables[0][i] = (i * PAGE_SIZE) | 3; /* Present | RW */
|
||||
}
|
||||
page_directory[0] = ((uint32_t)page_tables[0]) | 3;
|
||||
|
||||
/* Allocate and clear the heap page table */
|
||||
uint32_t heap_pd_index = HEAP_START >> 22; /* 0xC0000000 >> 22 = 768 */
|
||||
page_tables[heap_pd_index] = (page_table_entry_t*)alloc_page();
|
||||
memset(page_tables[heap_pd_index], 0, PAGE_SIZE);
|
||||
|
||||
/* Map 4MB heap pages */
|
||||
for (uint32_t i = 0; i < PAGE_TABLE_ENTRIES; i++) /* 1024 pages = 4MB */
|
||||
{
|
||||
void* phys = alloc_page();
|
||||
if (phys == 0)
|
||||
{
|
||||
printf("Out of physical memory during heap mapping!\n");
|
||||
while (1);
|
||||
}
|
||||
page_tables[heap_pd_index][i] = ((uint32_t)phys & 0xFFFFF000) | 3; /* Present | RW */
|
||||
}
|
||||
page_directory[heap_pd_index] = ((uint32_t)page_tables[heap_pd_index]) | 3;
|
||||
|
||||
/* Load page directory */
|
||||
asm volatile ("mov %0, %%cr3" : : "r"(page_directory));
|
||||
|
||||
/* Enable paging */
|
||||
_enable_paging_asm();
|
||||
}
|
||||
static uint32_t* page_directory;
|
||||
|
||||
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;
|
||||
uint32_t pd_idx = ((uint32_t)virt_addr >> 22) & 0x3FF;
|
||||
uint32_t pt_idx = ((uint32_t)virt_addr >> 12) & 0x3FF;
|
||||
|
||||
/* Allocate page table if necessary */
|
||||
if (!(page_directory[pd_index] & 1))
|
||||
uint32_t* page_table;
|
||||
|
||||
if (!(page_directory[pd_idx] & PAGE_PRESENT))
|
||||
{
|
||||
void* pt_phys = alloc_page();
|
||||
page_tables[pd_index] = (page_table_entry_t*)((uint32_t)pt_phys + 0xC0000000); /* Map it higher */
|
||||
|
||||
memset(page_tables[pd_index], 0, PAGE_SIZE);
|
||||
|
||||
page_directory[pd_index] = ((uint32_t)pt_phys) | 0x3; /* Present, R/W */
|
||||
page_table = (uint32_t*) pmm_alloc_page();
|
||||
MEMSET(page_table, 0, PAGE_SIZE);
|
||||
page_directory[pd_idx] = ((uint32_t)page_table) | PAGE_PRESENT | PAGE_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
page_table = (uint32_t*)(page_directory[pd_idx] & ~0xFFF);
|
||||
}
|
||||
|
||||
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");
|
||||
page_table[pt_idx] = ((uint32_t)phys_addr) | PAGE_PRESENT | PAGE_WRITE;
|
||||
}
|
||||
|
||||
void paging_init(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
printf("[ PAGING ] Initializing paging...\n");
|
||||
#endif
|
||||
|
||||
page_directory = (uint32_t*)pmm_alloc_page();
|
||||
|
||||
MEMSET(page_directory, 0, PAGE_SIZE);
|
||||
|
||||
for (uint32_t addr = 0; addr < 0x800000; addr += PAGE_SIZE)
|
||||
{
|
||||
map_page((void*) addr, (void*) addr); /* identity map first 8MB */
|
||||
}
|
||||
|
||||
asm volatile("mov %0, %%cr3" :: "r"(page_directory));
|
||||
uint32_t cr0;
|
||||
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||
cr0 |= 0x80000000;
|
||||
asm volatile("mov %0, %%cr0" :: "r"(cr0));
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PAGING ] Paging initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
98
lib/mm/pmm.c
98
lib/mm/pmm.c
@ -1,80 +1,76 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.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;
|
||||
#define MAX_PAGES (1024 * 1024) /* 4GB / 4KB */
|
||||
static uint8_t bitmap[MAX_PAGES / 8] __attribute__((section(".pmm_bitmap")));
|
||||
static size_t total_pages;
|
||||
|
||||
static inline void set_bit(uint32_t idx)
|
||||
#define BITMAP_SET(i) (bitmap[(i) / 8] |= (1 << ((i) % 8)))
|
||||
#define BITMAP_CLEAR(i) (bitmap[(i) / 8] &= ~(1 << ((i) % 8)))
|
||||
#define BITMAP_TEST(i) (bitmap[(i) / 8] & (1 << ((i) % 8)))
|
||||
|
||||
void pmm_init(multiboot_info_t* mb)
|
||||
{
|
||||
bitmap[idx / 8] |= (1 << (idx % 8));
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Initializing physical memory manager...\n");
|
||||
#endif
|
||||
|
||||
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++)
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
for (uint32_t i = 0; i < (total_pages / 8); i++)
|
||||
{
|
||||
bitmap[i] = 0xFF; /* Mark all as used */
|
||||
bitmap[i] = 0xFF;
|
||||
}
|
||||
|
||||
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)
|
||||
multiboot_memory_map_t* mmap = (void*)(uintptr_t)mb->mmap_addr;
|
||||
size_t entries = mb->mmap_length / sizeof(multiboot_memory_map_t);
|
||||
|
||||
for (size_t i = 0; i < entries; i++)
|
||||
{
|
||||
if (mmap->type == 1) /* Usable */
|
||||
if (mmap[i].type == 1) /* usable */
|
||||
{
|
||||
uint64_t base = mmap->addr;
|
||||
uint64_t len = mmap->len;
|
||||
for (uint64_t addr = base; addr < base + len; addr += PAGE_SIZE)
|
||||
uint64_t start = mmap[i].addr;
|
||||
uint64_t end = start + mmap[i].len;
|
||||
for (uint64_t addr = start; addr < end; addr += 0x1000)
|
||||
{
|
||||
if (addr >= 0x210000) /* Skip first 2.1MB, or ≈ 2.06MiB */
|
||||
if (addr >= 0x100000) /* skip below 1MB */
|
||||
{
|
||||
uint32_t idx = addr / PAGE_SIZE;
|
||||
|
||||
if (idx >= total_pages)
|
||||
{
|
||||
continue; /* skip entries above 4GB */
|
||||
}
|
||||
|
||||
clear_bit(idx);
|
||||
used_pages--;
|
||||
size_t idx = addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
mmap = (multiboot_memory_map_t*)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
|
||||
}
|
||||
total_pages = MAX_PAGES;
|
||||
|
||||
#ifdef _DEBUG
|
||||
printf("[ PMM ] Physical memory manager initialized\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void* alloc_page(void) {
|
||||
for (uint32_t i = 0; i < total_pages; i++)
|
||||
void* pmm_alloc_page(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < total_pages; ++i)
|
||||
{
|
||||
if (!test_bit(i))
|
||||
if (!BITMAP_TEST(i))
|
||||
{
|
||||
set_bit(i);
|
||||
used_pages++;
|
||||
return (void*)(i * PAGE_SIZE);
|
||||
BITMAP_SET(i);
|
||||
return (void*)(i * 4096);
|
||||
}
|
||||
}
|
||||
return NULL; /* Out of memory */
|
||||
|
||||
printf("pmm_alloc_page(): No free page found!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_page(void* ptr)
|
||||
|
||||
void pmm_free_page(void* addr)
|
||||
{
|
||||
uint32_t idx = (uint32_t)ptr / PAGE_SIZE;
|
||||
clear_bit(idx);
|
||||
size_t idx = (uintptr_t)addr / 0x1000;
|
||||
BITMAP_CLEAR(idx);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user