genusOS/src/alloc.c

197 lines
4.0 KiB
C

#include "alloc.h"
#include "common.h"
#include "print.h"
#include "../include/limine.h"
__attribute__((used, section(".limine_requests")))
static volatile struct limine_memmap_request mem_req = {
.id = LIMINE_MEMMAP_REQUEST_ID,
.revision = 0,
};
extern u32 fg, bg;
static void print_memmap_entry(struct limine_memmap_entry* entry) {
u32 savefg = fg;
u32 savebg = bg;
static const char* type_strs[] = {
"Usable",
"Reserved",
"ACPI Reclaimable",
"ACPI NVS",
"BAD!!!",
"Bootloader Reclaimable",
"Executable and Modules",
"Framebuffer",
"ACPI Tables",
};
static u32 type_colors[] = {
0x00AF00,
0xAF1F00,
0x7f7f00,
0x7f7f00,
0xFF0000,
0x007f7f,
0x408000,
0x0000FF,
0x00FF00
};
bg = type_colors[entry->type];
fg = ~bg;
u64 addr = entry->base;
u64 end = addr + entry->length;
print("[");
print(type_strs[entry->type]);
print("]");
print64(addr);
print(" - ");
print64(end);
print("\n");
fg = savefg;
bg = savebg;
}
static size_t total_pages;
static u8* alloc_start;
static u8* alloc_end;
static u8* alloc_next;
static u64* alloc_bitmap;
void alloc_init() {
print("Initializing Page Allocator\n");
if(!mem_req.response) {
print("Failed to get memory map :(\n)");
hang();
}
u64 largest_base = 0;
size_t largest_size = 0;
for(size_t i = 0; i < mem_req.response->entry_count; i++) {
struct limine_memmap_entry* entry = mem_req.response->entries[i];
print_memmap_entry(entry);
if(entry->type == LIMINE_MEMMAP_USABLE) {
if(entry->length > largest_size) {
largest_base = entry->base;
largest_size = entry->length;
print("\t\\LARGEST USABLE: ");
print64(entry->length >> 20);
print("MiB\n");
}
}
}
if(!largest_size) {
print("Couldn't find a free page!!!\n");
hang();
}
total_pages = largest_size / PAGE_SIZE;
size_t usage_bitmap_size = (total_pages + 7) / 8;
total_pages -= (usage_bitmap_size + PAGE_SIZE-1) / PAGE_SIZE;
alloc_bitmap = (u64*)(phys_to_virt(largest_base));
alloc_start = (u8*)(phys_to_virt(largest_base + usage_bitmap_size));
alloc_next = alloc_start;
alloc_end = (u8*)(phys_to_virt(largest_base + largest_size));
}
static size_t page(void* addr) {
return ((u8*)addr - alloc_start) / PAGE_SIZE;
}
static void* addr(size_t page) {
return alloc_start + page*PAGE_SIZE;
}
static void usepage(size_t page) {
size_t idx = page / 64;
size_t bit = page & 63;
alloc_bitmap[idx] |= (1 << bit);
}
static void usepagerange(size_t page, size_t len) {
for(size_t i = 0; i < len; len++) {
usepage(i + page);
}
}
static void unusepage(size_t page) {
size_t idx = page / 64;
size_t bit = page & 63;
alloc_bitmap[idx] &= ~(1 << bit);
}
static void unusepagerange(size_t page, size_t len) {
for(size_t i = 0; i < len; len++) {
unusepage(i+page);
}
}
static u8 getpageusage(size_t page) {
return (alloc_bitmap[page / 8] >> (page & 7)) & 1;
}
void dealloc(void* addr, size_t size) {
// adjust to page size
size_t pages = (size+PAGE_SIZE-1) / PAGE_SIZE;
unusepagerange(page(addr), pages);
}
void* alloc(size_t size) {
size_t pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
size_t page = 0;
if(pages == 0 || pages >= total_pages) {
return NULL;
}
size_t consecutive = 0;
for(size_t i = 0; i < pages; i++) {
u64 word = alloc_bitmap[i];
if(word == 0) {
if(!consecutive)
page = i * 64;
consecutive += 64;
if(consecutive >= pages) {
usepagerange(page, pages);
return addr(page);
}
continue;
}
if(word == ~0ULL) {
consecutive = 0;
page = -1;
}
for(size_t bit = 0; bit < 64; bit++) {
if((word & (1ULL << bit)) == 0) {
if(!consecutive)
page = i * 64 + bit;
if(++consecutive >= pages) {
usepagerange(page, pages);
return addr(pages);
}
} else {
consecutive = 0;
page = -1;
}
}
}
return NULL;
}