diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2025-02-01 09:23:01 -0500 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2025-02-01 09:23:01 -0500 |
commit | 3c6e55df77bf373a5d51785afd8463bca9161c7c (patch) | |
tree | 2ca8b0b8641058b42fb13459cd8d3f260f5d7a28 /kernel/libk/liballoc.cc | |
parent | 4111fee72bcde6db229fc45b0076db8bc7407937 (diff) |
libk: kmalloc->liballoc && C->C++
Diffstat (limited to 'kernel/libk/liballoc.cc')
-rw-r--r-- | kernel/libk/liballoc.cc | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/kernel/libk/liballoc.cc b/kernel/libk/liballoc.cc new file mode 100644 index 0000000..6f48557 --- /dev/null +++ b/kernel/libk/liballoc.cc @@ -0,0 +1,280 @@ +/* + + * bubbl + * Copyright (C) 2025 Raghuram Subramani <raghus2247@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <kernel/spinlock.h> +#include <libk/liballoc.h> +#include <libk/stdio.h> +#include <mm/virtual_mm.h> +#include <stddef.h> +#include <stdint.h> + +/* TODO: Kmalloc must have space for a page table *at all times*. */ + +#define LIBALLOC_MAGIC 0xc001c0de +#define MAXCOMPLETE 5 +#define MAXEXP 32 +#define MINEXP 8 + +#define MODE_BEST 0 +#define MODE_INSTANT 1 + +#define MODE MODE_BEST + +namespace LibAlloc +{ + +struct boundary_tag *l_freePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks +int l_completePages[MAXEXP]; //< Allowing for 2^MAXEXP blocks + +static unsigned int l_initialized = 0; //< Flag to indicate initialization. +static unsigned int l_pageSize = 4096; //< Individual page size +static unsigned int l_pageCount = 1; //< Minimum number of pages to allocate. + +spinlock_t lock; +bool kmalloc_initialized; + +#define liballoc_alloc VirtualMM::alloc_pages +#define liballoc_free VirtualMM::free_pages + +inline int +liballoc_lock(void) +{ + Spinlock::acquire(&lock); + return 0; +} + +inline int +liballoc_unlock(void) +{ + Spinlock::release(&lock); + return 0; +} + +bool +initialized(void) +{ + return kmalloc_initialized; +} + +void +initialize(void) +{ + // void *x = + kmalloc(1); + kmalloc_initialized = true; + // kfree(x); +} + +static inline int +getexp(int size) +{ + if (size < (1 << MINEXP)) { + return -1; // Smaller than the quantum. + } + + int shift = MINEXP; + + while (shift < MAXEXP) { + if ((1 << shift) > size) + break; + shift += 1; + } + + return shift - 1; +} + +static inline void +insert_tag(struct boundary_tag *tag, int index) +{ + int realIndex; + + if (index < 0) { + realIndex = getexp(tag->real_size - sizeof(struct boundary_tag)); + if (realIndex < MINEXP) + realIndex = MINEXP; + } else + realIndex = index; + + tag->index = realIndex; + + if (l_freePages[realIndex] != NULL) { + l_freePages[realIndex]->prev = tag; + tag->next = l_freePages[realIndex]; + } + + l_freePages[realIndex] = tag; +} + +static inline void +remove_tag(struct boundary_tag *tag) +{ + if (l_freePages[tag->index] == tag) + l_freePages[tag->index] = tag->next; + + if (tag->prev != NULL) + tag->prev->next = tag->next; + if (tag->next != NULL) + tag->next->prev = tag->prev; + + tag->next = NULL; + tag->prev = NULL; + tag->index = -1; +} + +static inline struct boundary_tag * +split_tag(struct boundary_tag *tag) +{ + unsigned int remainder + = tag->real_size - sizeof(struct boundary_tag) - tag->size; + + struct boundary_tag *new_tag + = (struct boundary_tag *) ((unsigned int) tag + + sizeof(struct boundary_tag) + tag->size); + + new_tag->magic = LIBALLOC_MAGIC; + new_tag->real_size = remainder; + + new_tag->next = NULL; + new_tag->prev = NULL; + + new_tag->split_left = tag; + new_tag->split_right = tag->split_right; + + if (new_tag->split_right != NULL) + new_tag->split_right->split_left = new_tag; + tag->split_right = new_tag; + + tag->real_size -= new_tag->real_size; + + insert_tag(new_tag, -1); + + return new_tag; +} + +static struct boundary_tag * +allocate_new_tag(unsigned int size) +{ + unsigned int pages; + unsigned int usage; + struct boundary_tag *tag; + + // This is how much space is required. + usage = size + sizeof(struct boundary_tag); + + // Perfect amount of space + pages = usage / l_pageSize; + if ((usage % l_pageSize) != 0) + pages += 1; + + // Make sure it's >= the minimum size. + if (pages < l_pageCount) + pages = l_pageCount; + + tag = (struct boundary_tag *) liballoc_alloc(pages); + + if (tag == NULL) + return NULL; // uh oh, we ran out of memory. + + tag->magic = LIBALLOC_MAGIC; + tag->size = size; + tag->real_size = pages * l_pageSize; + tag->index = -1; + + tag->next = NULL; + tag->prev = NULL; + tag->split_left = NULL; + tag->split_right = NULL; + + return tag; +} + +void * +kmalloc(size_t size) +{ + int index; + void *ptr; + struct boundary_tag *tag = NULL; + + liballoc_lock(); + + if (l_initialized == 0) { + for (index = 0; index < MAXEXP; index++) { + l_freePages[index] = NULL; + l_completePages[index] = 0; + } + l_initialized = 1; + } + + index = getexp(size) + MODE; + if (index < MINEXP) + index = MINEXP; + + // Find one big enough. + tag = l_freePages[index]; // Start at the front of the list. + while (tag != NULL) { + // If there's enough space in this tag. + if ((tag->real_size - sizeof(struct boundary_tag)) + >= (size + sizeof(struct boundary_tag))) { + break; + } + + tag = tag->next; + } + + // No page found. Make one. + if (tag == NULL) { + if ((tag = allocate_new_tag(size)) == NULL) { + liballoc_unlock(); + return NULL; + } + + index = getexp(tag->real_size - sizeof(struct boundary_tag)); + } else { + remove_tag(tag); + + if ((tag->split_left == NULL) && (tag->split_right == NULL)) + l_completePages[index] -= 1; + } + + // We have a free page. Remove it from the free pages list. + + tag->size = size; + + // Removed... see if we can re-use the excess space. + + unsigned int remainder + = tag->real_size - size + - sizeof(struct boundary_tag) * 2; // Support a new tag + remainder + + if (((int) (remainder) + > 0) /*&& ( (tag->real_size - remainder) >= (1<<MINEXP))*/) { + int childIndex = getexp(remainder); + + if (childIndex >= 0) { + struct boundary_tag *new_tag = split_tag(tag); + (void) new_tag; + } + } + + ptr = (void *) ((unsigned int) tag + sizeof(struct boundary_tag)); + liballoc_unlock(); + return ptr; +} + +} |