210 lines
6.5 KiB
C
210 lines
6.5 KiB
C
#include "arch/amd64/mm/heap.h"
|
|
#include "sys/string.h"
|
|
#include "sys/assert.h"
|
|
#include "sys/panic.h"
|
|
#include "sys/debug.h"
|
|
#include "sys/spin.h"
|
|
#include "sys/mm.h"
|
|
|
|
#define HEAP_MAGIC 0x1BAD83A0
|
|
|
|
typedef struct heap_block {
|
|
uint32_t magic;
|
|
uint32_t size;
|
|
struct heap_block *prev, *next;
|
|
} heap_block_t;
|
|
|
|
static struct kernel_heap {
|
|
uintptr_t phys_base;
|
|
size_t limit;
|
|
} amd64_global_heap;
|
|
heap_t *heap_global = &amd64_global_heap;
|
|
|
|
static spin_t heap_lock = 0;
|
|
|
|
#if defined(HEAP_TRACE)
|
|
void heap_trace(int type, const char *file, const char *func, int line, void *ptr, size_t count) {
|
|
if (type == HEAP_TRACE_ALLOC) {
|
|
// Don't want fucktons of ACPI crap
|
|
if (strncmp(func, "Acpi", 4)) {
|
|
debugf(DEBUG_DEFAULT, "\033[31m%s:%u: %s allocated %S == %p\033[0m\n", file, line, func, count, ptr);
|
|
}
|
|
} else {
|
|
// Don't want fucktons of ACPI crap
|
|
if (strncmp(func, "Acpi", 4)) {
|
|
debugf(DEBUG_DEFAULT, "\033[32m%s:%u: %s freed %p\033[0m\n", file, line, func, ptr);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void heap_stat(heap_t *heap, struct heap_stat *st) {
|
|
uintptr_t irq;
|
|
spin_lock_irqsave(&heap_lock, &irq);
|
|
heap_block_t *begin = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
|
|
|
|
st->alloc_count = 0;
|
|
st->alloc_size = 0;
|
|
st->free_size = 0;
|
|
st->total_size = heap->limit;
|
|
|
|
for (heap_block_t *block = begin; block; block = block->next) {
|
|
if ((block->magic & HEAP_MAGIC) != HEAP_MAGIC) {
|
|
panic("Broken heap");
|
|
}
|
|
if (block->magic & 1) {
|
|
++st->alloc_count;
|
|
st->alloc_size += block->size;
|
|
} else {
|
|
st->free_size += block->size;
|
|
}
|
|
}
|
|
spin_release_irqrestore(&heap_lock, &irq);
|
|
}
|
|
|
|
void amd64_heap_init(heap_t *heap, uintptr_t phys_base, size_t sz) {
|
|
heap->phys_base = phys_base;
|
|
heap->limit = sz;
|
|
|
|
// Create a single whole-heap block
|
|
heap_block_t *block = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
|
|
|
|
uint32_t s = 13;
|
|
for (size_t i = 0; i < sz; ++i) {
|
|
s ^= s << 13;
|
|
s ^= s >> 17;
|
|
s ^= s << 5;
|
|
((uint8_t *) block)[i] = s;
|
|
}
|
|
|
|
block->magic = HEAP_MAGIC;
|
|
block->next = NULL;
|
|
block->prev = NULL;
|
|
block->size = sz - sizeof(heap_block_t);
|
|
}
|
|
|
|
// Heap interface implementation
|
|
void *heap_alloc(heap_t *heap, size_t count) {
|
|
uintptr_t irq;
|
|
spin_lock_irqsave(&heap_lock, &irq);
|
|
heap_block_t *begin = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
|
|
|
|
// Some alignment fuck ups led me to this
|
|
count = (count + 15) & ~15;
|
|
|
|
for (heap_block_t *block = begin; block; block = block->next) {
|
|
if ((block->magic & HEAP_MAGIC) != HEAP_MAGIC) {
|
|
panic("Heap is broken: magic %08x, %p (%lu), size could be %S\n", block->magic, block, (uintptr_t) block - (uintptr_t) begin, block->size);
|
|
}
|
|
}
|
|
|
|
for (heap_block_t *block = begin; block; block = block->next) {
|
|
if (block->magic & 1) {
|
|
continue;
|
|
}
|
|
|
|
if (count == block->size) {
|
|
block->magic |= 1;
|
|
spin_release_irqrestore(&heap_lock, &irq);
|
|
return (void *) ((uintptr_t) block + sizeof(heap_block_t));
|
|
} else if (block->size >= count + sizeof(heap_block_t)) {
|
|
// Insert new block after this one
|
|
heap_block_t *cur_next = block->next;
|
|
heap_block_t *new_block = (heap_block_t *) (((uintptr_t) block) + sizeof(heap_block_t) + count);
|
|
if (cur_next) {
|
|
cur_next->prev = new_block;
|
|
}
|
|
new_block->next = cur_next;
|
|
new_block->prev = block;
|
|
new_block->size = block->size - sizeof(heap_block_t) - count;
|
|
new_block->magic = HEAP_MAGIC;
|
|
block->next = new_block;
|
|
block->size = count;
|
|
block->magic |= 1;
|
|
spin_release_irqrestore(&heap_lock, &irq);
|
|
return (void *) ((uintptr_t) block + sizeof(heap_block_t));
|
|
}
|
|
}
|
|
|
|
spin_release_irqrestore(&heap_lock, &irq);
|
|
return NULL;
|
|
}
|
|
|
|
void heap_free(heap_t *heap, void *ptr) {
|
|
if (!ptr) {
|
|
return;
|
|
}
|
|
uintptr_t irq;
|
|
spin_lock_irqsave(&heap_lock, &irq);
|
|
|
|
if (ptr == (void *) 0xffffff00042ddd70) {
|
|
}
|
|
|
|
// Check if the pointer belongs to the heap
|
|
if (((uintptr_t) ptr) < MM_VIRTUALIZE(heap->phys_base) ||
|
|
((uintptr_t) ptr) > (MM_VIRTUALIZE(heap->phys_base) + heap->limit)) {
|
|
panic("Tried to free a pointer from outside a heap: %p\n", ptr);
|
|
}
|
|
|
|
// Check if ptr is in a valid block
|
|
heap_block_t *block = (heap_block_t *) (((uintptr_t) ptr) - sizeof(heap_block_t));
|
|
|
|
assert((block->magic & HEAP_MAGIC) == HEAP_MAGIC, "Corrupted heap block magic: %p\n", ptr);
|
|
assert(block->magic & 1, "Double free error (kheap): %p\n", ptr);
|
|
|
|
block->magic = HEAP_MAGIC;
|
|
//kdebug("%p is free\n", block);
|
|
heap_block_t *begin = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
|
|
|
|
for (heap_block_t *block = begin; block; block = block->next) {
|
|
if ((block->magic & HEAP_MAGIC) != HEAP_MAGIC) {
|
|
panic("Heap is broken: magic %08x, %p (%lu), size could be %S\n", block->magic, block, (uintptr_t) block - (uintptr_t) begin, block->size);
|
|
}
|
|
}
|
|
|
|
heap_block_t *prev = block->prev;
|
|
heap_block_t *next = block->next;
|
|
|
|
// TODO: fix this
|
|
if (prev && !(prev->magic & 1)) {
|
|
prev->next = next;
|
|
if (next) {
|
|
next->prev = prev;
|
|
}
|
|
prev->size += sizeof(heap_block_t) + block->size;
|
|
block->magic = 0;
|
|
block = prev;
|
|
}
|
|
|
|
if (next && !(next->magic & 1)) {
|
|
block->next = next->next;
|
|
if (next->next) {
|
|
next->next->prev = block;
|
|
}
|
|
next->magic = 0;
|
|
block->size += sizeof(heap_block_t) + next->size;
|
|
}
|
|
|
|
spin_release_irqrestore(&heap_lock, &irq);
|
|
}
|
|
|
|
// amd64-specific
|
|
size_t amd64_heap_blocks(const heap_t *heap) {
|
|
size_t c = 0;
|
|
for (const heap_block_t *block = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
|
|
block; block = block->next) {
|
|
assert((block->magic & HEAP_MAGIC) == HEAP_MAGIC, "Corrupted heap block magic\n");
|
|
++c;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
void amd64_heap_dump(const heap_t *heap) {
|
|
for (const heap_block_t *block = (heap_block_t *) MM_VIRTUALIZE(heap->phys_base);
|
|
block; block = block->next) {
|
|
assert((block->magic & HEAP_MAGIC) == HEAP_MAGIC, "Corrupted heap block magic\n");
|
|
|
|
kdebug("%p: %S %s%s\n", block, block->size, (block->magic & 1 ? "USED" : "FREE"), (block->next ? " -> " : ""));
|
|
}
|
|
}
|