[MEMORY] Very simple malloc implementation for kernel

This commit is contained in:
Thomas Lovén 2016-08-13 23:42:53 +02:00
parent 4bf5835dc4
commit deb1f031ce
3 changed files with 185 additions and 0 deletions

View File

@ -19,6 +19,19 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data)
extern void *BootGDT;
vmm_set_page(0, V2P(&BootGDT), V2P(&BootGDT), PAGE_PRESENT);
void *a = kmalloc(0x400);
void *b = kmalloc(0x200);
void *c = kmalloc(0x100);
kfree(b);
void *d = kmalloc(0x100);
(void)a;
(void)b;
(void)c;
(void)d;
heap_print();
debug_info("BOOT COMPLETE\n");
for(;;)asm("hlt");
}

View File

@ -1,6 +1,7 @@
#pragma once
#define KERNEL_OFFSET 0xFFFFFF8000000000
#define KERNEL_HEAP_S 0xFFFFFFC000000000
#ifdef __ASSEMBLER__
#define V2P(a) ((a) - KERNEL_OFFSET)
@ -37,6 +38,8 @@
#define PAGE_GLOBAL 0x100
#ifndef __ASSEMBLER__
#include <stddef.h>
typedef void * page_table;
extern page_table BootP4;
@ -54,4 +57,10 @@ void vmm_set_P4(page_table *P4);
void vmm_free_P4(page_table *P4);
uintptr_t vmm_get_page(page_table *P4, uintptr_t addr);
uintptr_t vmm_set_page(page_table *P4, uintptr_t addr, uintptr_t phys, uint32_t flags);
void kfree(void *a);
void *kmalloc(size_t size);
void *kcalloc(size_t count, size_t size);
void *krealloc(void *ptr, size_t size);
void heap_print();
#endif

163
kernel/mem/heap.c Normal file
View File

@ -0,0 +1,163 @@
#include <mem.h>
#include <stdint.h>
#include <stddef.h>
#include <debug.h>
#include <string.h>
typedef struct chunk_st
{
struct chunk_st *p, *n;
uint8_t flags;
size_t size;
uint8_t data[];
} chunk_t;
#define CHUNK_FREE 0x1
uintptr_t heap_max = KERNEL_HEAP_S;
uintptr_t brk = KERNEL_HEAP_S;
chunk_t *heap = 0;
void *ksbrk(size_t size)
{
// This can only be used to increase the size of the kernel heap
// for now...
while(brk < heap_max + size)
{
vmm_set_page(0, brk, (uintptr_t)pmm_alloc(), PAGE_PRESENT | PAGE_WRITE);
brk += PAGE_SIZE;
}
heap_max += size;
return (void *)heap_max;
}
void merge_chunk(chunk_t *c)
{
// Join free chunks together if they are next to each other
if(c->n && c->n->flags & CHUNK_FREE) // Merge with next
{
// Update size
c->size += c->n->size + sizeof(chunk_t);
// Update list
c->n = c->n->n;
if(c->n)
c->n->p = c;
}
if(c->p && c->p->flags & CHUNK_FREE) // Merge with previous
{
// Update size
c->p->size += c->size + sizeof(chunk_t);
// Update list
c->p->n = c->n;
if(c->n)
c->n->p = c->p;
}
}
void split_chunk(chunk_t *c, size_t size)
{
// Split a chunk into one of given size and one of with the rest
if(c->size <= size + sizeof(chunk_t))
return;
// Split off as much as isn't needed
chunk_t *c2 = incptr(c->data, size);
c2->size = c->size - size - sizeof(chunk_t);
c2->flags = CHUNK_FREE;
// Insert into list
c2->n = c->n;
if(c2->n) c2->n->p = c2;
c->n = c2;
c2->p = c;
// Change size of first chunk
c->size = size;
}
void kfree(void *a)
{
if((uintptr_t)a < KERNEL_HEAP_S || (uintptr_t)a > heap_max)
{
debug_error("PANIC: kfree - Tried to free %x\n", a);
for(;;);
}
// Find chunk header and mark as free
chunk_t *c = incptr(a, -sizeof(chunk_t));
c->flags = CHUNK_FREE;
merge_chunk(c);
}
void *kmalloc(size_t size)
{
chunk_t *c = heap, *p = 0;
while(c)
{
// Linear search of list for free chunk
if((c->flags & CHUNK_FREE) && c->size >= size)
{
// A large enough free chunk has been found
// adjust and return
split_chunk(c, size);
c->flags = 0;
return (void *)c->data;
}
p = c;
c = c->n;
}
// No free chunk of right size found
// increase heap size
if(p)
{
c = incptr(p, p->size + sizeof(chunk_t));
} else {
c = heap = (chunk_t *)heap_max;
}
void *end = ksbrk(size + sizeof(chunk_t));
// Add a new chunk
c->size = (uintptr_t)end - (uintptr_t)c->data;
c->flags = CHUNK_FREE;
c->n = c->p = 0;
c->p = p;
if(p) c->n = p->n;
if(p) p->n = c;
// And try again...
return kmalloc(size);
}
void *kcalloc(size_t count, size_t size)
{
void *ptr = kmalloc(count*size);
memset(ptr, 0, count*size);
return ptr;
}
void *krealloc(void *ptr, size_t size)
{
void *new = kmalloc(size);
if(ptr)
{
memcpy(new, ptr, size);
kfree(ptr);
}
return new;
}
void heap_print()
{
// Print all heap chunks
chunk_t *c = heap;
debug_info("Heap map:\n");
while(c)
{
debug("s:%x f:%x\n", c->size, c->flags);
c = c->n;
}
}