Files
osc2025/kernel/lib/kmalloc.c
2025-04-08 06:59:50 +08:00

115 lines
3.0 KiB
C

#include <uart.h>
#include <errcode.h>
#include <utils.h>
#include <kmalloc.h>
#include <stddef.h>
#include <mman.h>
extern uint64_t __heap_start;
extern uint64_t __heap_end;
void *(*kmalloc)(size_t size) = simple_alloc;
void (*kfree)(void *ptr) = (void (*)(void *))0x0;
kmalloc_allocator_t mman_kmalloc_pool[KMALLOC_MAX_ALLOCATOR_SIZE + 1];
void *_heap_top = (void *)0x0;
void init_mman_kmalloc()
{
for (int i = 1; i <= KMALLOC_MAX_ALLOCATOR_SIZE; ++i)
mman_kmalloc_pool[i] = (kmalloc_allocator_t){
.left = 0,
.page_begin = (kmalloc_header_t *)0x0,
};
kmalloc = mman_alloc;
kfree = mman_free;
}
// simple 8-byte aligned linear allocation
void *simple_alloc(size_t size)
{
if (!_heap_top) {
_heap_top = (void *)&__heap_start;
}
size = (size_t)ALIGN8(size);
if ((uint64_t)_heap_top + size >= (uint64_t)&__heap_end)
exit(ERR_NO_MEM);
void *ret = _heap_top;
_heap_top = (void *)((uint64_t)_heap_top + size);
return ret;
}
#define PAGE_HEADER(ptr) ((kmalloc_header_t *)(((uint64_t)(ptr) >> 12) << 12))
void *mman_alloc(size_t unit)
{
unit = (size_t)ALIGN8(unit);
if (unit > (KMALLOC_MAX_ALLOCATOR_SIZE << 3))
return allocate_page(((unit - 1) >> 12) + 1);
kmalloc_allocator_t *pool = &mman_kmalloc_pool[unit >> 3];
if (!pool->left) {
void *page = allocate_page(1), *ptr = page + sizeof(kmalloc_header_t);
*(kmalloc_header_t *)page = (kmalloc_header_t){
.unit = unit,
.left = (PAGE_SIZE - sizeof(kmalloc_header_t)) / unit,
.begin = page + sizeof(kmalloc_header_t),
.page_prev = (kmalloc_header_t *)0x0,
.page_next = (kmalloc_header_t *)0x0,
};
*pool = (kmalloc_allocator_t){
.left = ((kmalloc_header_t *)page)->left,
.page_begin = (kmalloc_header_t *)page,
};
for (; ptr + unit <= page + PAGE_SIZE; ptr += unit)
*(void **)ptr = ptr + unit;
}
void *ret = pool->page_begin->begin;
pool->page_begin->begin = *(void **)pool->page_begin->begin;
--pool->left;
--pool->page_begin->left;
if (!pool->page_begin->left)
pool->page_begin = *(void **)pool->page_begin->page_next;
return ret;
}
void mman_free(void *ptr)
{
if (ptr == ALIGN4K(ptr)) {
free_page(ptr);
return;
}
size_t unit = PAGE_HEADER(ptr)->unit;
kmalloc_allocator_t *pool = &mman_kmalloc_pool[unit >> 3];
if (!PAGE_HEADER(ptr)->left) {
PAGE_HEADER(ptr)->page_next = pool->page_begin;
pool->page_begin->page_prev = PAGE_HEADER(ptr);
pool->page_begin = PAGE_HEADER(ptr);
}
*(void **)ptr = pool->page_begin->begin;
pool->page_begin->begin = ptr;
++pool->left;
++PAGE_HEADER(ptr)->left;
size_t cap = (PAGE_SIZE - sizeof(kmalloc_allocator_t)) / unit;
if (PAGE_HEADER(ptr)->left == cap && pool->left >= 2 * cap) {
if (PAGE_HEADER(ptr)->page_prev)
PAGE_HEADER(ptr)->page_prev->page_next = PAGE_HEADER(ptr)->page_next;
if (PAGE_HEADER(ptr)->page_next)
PAGE_HEADER(ptr)->page_next->page_prev = PAGE_HEADER(ptr)->page_prev;
free_page(PAGE_HEADER(ptr));
}
}