mirror of
https://github.com/Tom-on64/kern.git
synced 2026-11-03 18:22:22 +00:00
125 lines
3.6 KiB
C
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
|