Files
kern/include/memory/malloc.h
T

125 lines
3.6 KiB
C

#ifndef MALLOC_H
#define MALLOC_H
#include <stdint.h>
#include <memory/virtual.h>
#include <memory/physical.h>
#include <stdbool.h>
// Singly linked list!
typedef struct mallocNode_s {
uint32_t size;
bool free;
struct mallocNode_s* next;
} mallocNode_t;
mallocNode_t* mallocListHead = NULL;
static uint32_t mallocVirtualAddr = 0;
static uint32_t mallocPhysicalAddr = 0;
static uint32_t mallocPages = 0;
void mallocInit(uint32_t size) {
mallocPages = size / PAGE_SIZE;
if (size % PAGE_SIZE > 0) { mallocPages++; }
mallocPhysicalAddr = (uint32_t)allocBlocks(mallocPages);
mallocListHead = (mallocNode_t*)mallocVirtualAddr;
// Map pages
for (uint32_t i = 0, virtualAddr = mallocVirtualAddr; i < mallocPages; i++, virtualAddr += PAGE_SIZE) {
mapPage((void*)(mallocPhysicalAddr + i * PAGE_SIZE), (void*)virtualAddr);
ptEntry_t* page = getPage(virtualAddr);
SET_ATTR(page, PTE_READ_WRITE);
}
if (mallocListHead) {
mallocListHead->size = (mallocPages * PAGE_SIZE) - sizeof(mallocNode_t);
mallocListHead->free = true;
mallocListHead->next = NULL;
}
}
void mallocSplit(mallocNode_t* node, uint32_t size) {
if (node->size < size + sizeof(mallocNode_t)) { return; } // Can't split - node too small
// Remainder node
mallocNode_t* newNode = (mallocNode_t*)((void*)node + size + sizeof(mallocNode_t));
newNode->size = node->size - size - sizeof(mallocNode_t);
newNode->free = true;
newNode->next = node->next;
// Split node
node->size = size;
node->free = false;
node->next = newNode;
}
void* mallocNextNode(uint32_t size) {
if (size == 0) { return NULL; } // Why would you try that? (undefined behaviour i guess)
mallocNode_t* current = mallocListHead;
if (mallocListHead->size == 0) { mallocInit(size); }
while (((current->size < size) || !current->free) && current->next != NULL) {
current = current->next;
}
if (current->size == size) {
current->free = false;
} else if (current->size > size + sizeof(mallocNode_t)) {
mallocSplit(current, size); // Modifies current into the right size and makes it point to the remainder
} else { // There's no large enough node -> try to allocate more pages
uint8_t pageCount = 1;
while (current->size + pageCount * PAGE_SIZE < size + sizeof(mallocNode_t)) {
pageCount++;
}
// Allocate and map new pages
uint32_t virtualAddr = mallocVirtualAddr + mallocPages * PAGE_SIZE;
for (uint32_t i = 0; i < pageCount; i++) {
ptEntry_t page = 0;
uint32_t* temp = allocPage(&page);
mapPage((void*)temp, (void*)virtualAddr);
SET_ATTR(&page, PTE_READ_WRITE);
virtualAddr += PAGE_SIZE;
current->size += PAGE_SIZE;
mallocPages++;
}
mallocSplit(current, size);
}
return (void*)current + sizeof(mallocNode_t);
}
void mallocMergeFree() {
mallocNode_t* current = mallocListHead;
while (current && current->next != NULL) {
if (current->free && current->next->free) {
current->size += (current->next->size) + sizeof(mallocNode_t);
current->next = current->next->next;
}
current = current->next;
}
}
void mallocFree(void* ptr) {
mallocNode_t* current = mallocListHead;
while (current->next) {
if ((void*)current + sizeof(mallocNode_t) == ptr) {
current->free = true;
mallocMergeFree();
break;
}
current = current->next;
}
}
#endif