diff --git a/yak-kernel/include/yak/rt/core/mem/liballoc.h b/yak-kernel/include/yak/rt/core/mem/liballoc.h new file mode 100644 index 0000000..ad176ae --- /dev/null +++ b/yak-kernel/include/yak/rt/core/mem/liballoc.h @@ -0,0 +1,83 @@ +#ifndef YAK_LIBALLOC_H +#define YAK_LIBALLOC_H + +#include +#include + +// retrieved from https://github.com/blanham/liballoc/blob/master/liballoc_1_1.h + +/** \defgroup ALLOCHOOKS liballoc hooks + * + * These are the OS specific functions which need to + * be implemented on any platform that the library + * is expected to work on. + */ + +/** @{ */ + + + +// If we are told to not define our own size_t, then we skip the define. +//#define _HAVE_UINTPTR_T +//typedef unsigned long uintptr_t; + +//This lets you prefix malloc and friends +//#define PREFIX(func) k ## func +#define PREFIX(func) func + +#ifdef __cplusplus +extern "C" { +#endif + + +/** This function is supposed to lock the memory data structures. It + * could be as simple as disabling interrupts or acquiring a spinlock. + * It's up to you to decide. + * + * \return 0 if the lock was acquired successfully. Anything else is + * failure. + */ +extern int liballoc_lock(); + +/** This function unlocks what was previously locked by the liballoc_lock + * function. If it disabled interrupts, it enables interrupts. If it + * had acquiried a spinlock, it releases the spinlock. etc. + * + * \return 0 if the lock was successfully released. + */ +extern int liballoc_unlock(); + +/** This is the hook into the local system which allocates pages. It + * accepts an integer parameter which is the number of pages + * required. The page size was set up in the liballoc_init function. + * + * \return NULL if the pages were not allocated. + * \return A pointer to the allocated memory. + */ +extern void *liballoc_alloc(size_t); + +/** This frees previously allocated memory. The void* parameter passed + * to the function is the exact same value returned from a previous + * liballoc_alloc call. + * + * The integer value is the number of pages to free. + * + * \return 0 if the memory was successfully freed. + */ +extern int liballoc_free(void *, size_t); + + +extern void *PREFIX(malloc)(size_t); ///< The standard function. +extern void *PREFIX(realloc)(void *, size_t); ///< The standard function. +extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function. +extern void PREFIX(free)(void *); ///< The standard function. + + +#ifdef __cplusplus +} +#endif + + +/** @} */ + +#endif \ No newline at end of file diff --git a/yak-kernel/include/yak/rt/core/mem/memmap.h b/yak-kernel/include/yak/rt/core/mem/memmap.h new file mode 100644 index 0000000..cb27812 --- /dev/null +++ b/yak-kernel/include/yak/rt/core/mem/memmap.h @@ -0,0 +1,20 @@ +// +// Created by rick on 18-10-23. +// + +#ifndef YAK_MEMMAP_H +#define YAK_MEMMAP_H + +#define MMAP_TYPE_UNDEFINED 0 +#define MMAP_TYPE_AVAILABLE 1 +#define MMAP_TYPE_RESERVED 2 +#define MMAP_TYPE_ACPI_RECLAIMABLE 3 +#define MMAP_TYPE_NVS 4 +#define MMAP_TYPE_BADRAM 5 +#define MMAP_TYPE_KERNEL 6 +#define MMAP_TYPE_PAGING 7 +#define MMAP_LAST_TYPE MMAP_TYPE_PAGING + +void memmap_put_entry(uintptr_t address, size_t length, uint8_t type); + +#endif //YAK_MEMMAP_H diff --git a/yak-kernel/src/rt/boot/limine/limine.c b/yak-kernel/src/rt/boot/limine/limine.c index 8b7ea83..60b285f 100644 --- a/yak-kernel/src/rt/boot/limine/limine.c +++ b/yak-kernel/src/rt/boot/limine/limine.c @@ -9,6 +9,7 @@ #include #include #include +#include "yak/rt/core/mem/memmap.h" static struct limine_bootloader_info_request limine_bootloader_info_request = { .id = LIMINE_BOOTLOADER_INFO_REQUEST, @@ -34,6 +35,7 @@ struct limine_memmap_request limine_memmap_request = { }; void limine_init(); + struct limine_entry_point_request limine_entry_point_request = { .id = LIMINE_ENTRY_POINT_REQUEST, .revision = 0, @@ -101,6 +103,29 @@ void limine_terminal_kprint(char c) { limine_terminal_request.response->write(limine_terminal_request.response->terminals[0], &c, 1); } +uint8_t limmine_memmap_to_memmap_type(uint64_t type) { + switch (type) { + case LIMINE_MEMMAP_USABLE: + return MMAP_TYPE_AVAILABLE; + case LIMINE_MEMMAP_RESERVED: + return MMAP_TYPE_RESERVED; + case LIMINE_MEMMAP_ACPI_RECLAIMABLE: + return MMAP_TYPE_ACPI_RECLAIMABLE; + case LIMINE_MEMMAP_ACPI_NVS: + return MMAP_TYPE_NVS; + case LIMINE_MEMMAP_BAD_MEMORY: + return MMAP_TYPE_BADRAM; + case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE: + return MMAP_TYPE_RESERVED; + case LIMINE_MEMMAP_KERNEL_AND_MODULES: + return MMAP_TYPE_KERNEL; + case LIMINE_MEMMAP_FRAMEBUFFER: + return MMAP_TYPE_RESERVED; + default: + return MMAP_TYPE_BADRAM; + } +} + void limine_init() { if (limine_terminal_request.response != NULL && limine_terminal_request.response->terminal_count >= 1) { kprint_register(limine_terminal_kprint); @@ -112,6 +137,13 @@ void limine_init() { printf("Booted using limine from an unknown bootloader\n"); } + if (limine_memmap_request.response != NULL) { + for (int i = 0; i < limine_memmap_request.response->entry_count; ++i) { + struct limine_memmap_entry *entry = limine_memmap_request.response->entries[i]; + memmap_put_entry(entry->base, entry->length, limmine_memmap_to_memmap_type(entry->type)); + } + } + if (limine_kernel_file_request.response != NULL) { debug_store_info(limine_kernel_file_request.response->kernel_file->address); } diff --git a/yak-kernel/src/rt/core/mem/liballoc.c b/yak-kernel/src/rt/core/mem/liballoc.c new file mode 100644 index 0000000..746d653 --- /dev/null +++ b/yak-kernel/src/rt/core/mem/liballoc.c @@ -0,0 +1,769 @@ +#include + +// retrieved from https://github.com/blanham/liballoc/blob/master/liballoc_1_1.c + +/** Durand's Amazing Super Duper Memory functions. */ + +#define VERSION "1.1" +#define ALIGNMENT 16ul//4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff. + +#define ALIGN_TYPE char ///unsigned char[16] /// unsigned short +#define ALIGN_INFO sizeof(ALIGN_TYPE)*16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there. + + +#define USE_CASE1 +#define USE_CASE2 +#define USE_CASE3 +#define USE_CASE4 +#define USE_CASE5 + + +/** This macro will conveniently align our pointer upwards */ +#define ALIGN(ptr) \ + if ( ALIGNMENT > 1 ) \ + { \ + uintptr_t diff; \ + ptr = (void*)((uintptr_t)ptr + ALIGN_INFO); \ + diff = (uintptr_t)ptr & (ALIGNMENT-1); \ + if ( diff != 0 ) \ + { \ + diff = ALIGNMENT - diff; \ + ptr = (void*)((uintptr_t)ptr + diff); \ + } \ + *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)) = \ + diff + ALIGN_INFO; \ + } + + +#define UNALIGN(ptr) \ + if ( ALIGNMENT > 1 ) \ + { \ + uintptr_t diff = *((ALIGN_TYPE*)((uintptr_t)ptr - ALIGN_INFO)); \ + if ( diff < (ALIGNMENT + ALIGN_INFO) ) \ + { \ + ptr = (void*)((uintptr_t)ptr - diff); \ + } \ + } + + +#define LIBALLOC_MAGIC 0xc001c0de +#define LIBALLOC_DEAD 0xdeaddead + +#if defined DEBUG || defined INFO +#include +#include + +#define FLUSH() fflush( stdout ) + +#endif + +/** A structure found at the top of all system allocated + * memory blocks. It details the usage of the memory block. + */ +struct liballoc_major { + struct liballoc_major *prev; ///< Linked list information. + struct liballoc_major *next; ///< Linked list information. + unsigned int pages; ///< The number of pages in the block. + unsigned int size; ///< The number of pages in the block. + unsigned int usage; ///< The number of bytes used in the block. + struct liballoc_minor *first; ///< A pointer to the first allocated memory in the block. +}; + + +/** This is a structure found at the beginning of all + * sections in a major block which were allocated by a + * malloc, calloc, realloc call. + */ +struct liballoc_minor { + struct liballoc_minor *prev; ///< Linked list information. + struct liballoc_minor *next; ///< Linked list information. + struct liballoc_major *block; ///< The owning block. A pointer to the major structure. + unsigned int magic; ///< A magic number to idenfity correctness. + unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more. + unsigned int req_size; ///< The size of memory requested. +}; + + +static struct liballoc_major *l_memRoot = NULL; ///< The root memory block acquired from the system. +static struct liballoc_major *l_bestBet = NULL; ///< The major with the most free memory. + +static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init. +static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init. +static unsigned long long l_allocated = 0; ///< Running total of allocated memory. +static unsigned long long l_inuse = 0; ///< Running total of used memory. + + +static long long l_warningCount = 0; ///< Number of warnings encountered +static long long l_errorCount = 0; ///< Number of actual errors +static long long l_possibleOverruns = 0; ///< Number of possible overruns + + + + + +// *********** HELPER FUNCTIONS ******************************* + +static void *liballoc_memset(void *s, int c, size_t n) { + unsigned int i; + for (i = 0; i < n; i++) + ((char *) s)[i] = c; + + return s; +} + +static void *liballoc_memcpy(void *s1, const void *s2, size_t n) { + char *cdest; + char *csrc; + unsigned int *ldest = (unsigned int *) s1; + unsigned int *lsrc = (unsigned int *) s2; + + while (n >= sizeof(unsigned int)) { + *ldest++ = *lsrc++; + n -= sizeof(unsigned int); + } + + cdest = (char *) ldest; + csrc = (char *) lsrc; + + while (n > 0) { + *cdest++ = *csrc++; + n -= 1; + } + + return s1; +} + + +#if defined DEBUG || defined INFO +static void liballoc_dump() +{ +#ifdef DEBUG + struct liballoc_major *maj = l_memRoot; + struct liballoc_minor *min = NULL; +#endif + + printf( "liballoc: ------ Memory data ---------------\n"); + printf( "liballoc: System memory allocated: %i bytes\n", l_allocated ); + printf( "liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse ); + printf( "liballoc: Warning count: %i\n", l_warningCount ); + printf( "liballoc: Error count: %i\n", l_errorCount ); + printf( "liballoc: Possible overruns: %i\n", l_possibleOverruns ); + +#ifdef DEBUG + while ( maj != NULL ) + { + printf( "liballoc: %x: total = %i, used = %i\n", + maj, + maj->size, + maj->usage ); + + min = maj->first; + while ( min != NULL ) + { + printf( "liballoc: %x: %i bytes\n", + min, + min->size ); + min = min->next; + } + + maj = maj->next; + } +#endif + + FLUSH(); +} +#endif + + + +// *************************************************************** + +static struct liballoc_major *allocate_new_page(unsigned int size) { + unsigned int st; + struct liballoc_major *maj; + + // This is how much space is required. + st = size + sizeof(struct liballoc_major); + st += sizeof(struct liballoc_minor); + + // Perfect amount of space? + if ((st % l_pageSize) == 0) + st = st / (l_pageSize); + else + st = st / (l_pageSize) + 1; + // No, add the buffer. + + + // Make sure it's >= the minimum size. + if (st < l_pageCount) st = l_pageCount; + + maj = (struct liballoc_major *) liballoc_alloc(st); + + if (maj == NULL) { + l_warningCount += 1; +#if defined DEBUG || defined INFO + printf( "liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st ); + FLUSH(); +#endif + return NULL; // uh oh, we ran out of memory. + } + + maj->prev = NULL; + maj->next = NULL; + maj->pages = st; + maj->size = st * l_pageSize; + maj->usage = sizeof(struct liballoc_major); + maj->first = NULL; + + l_allocated += maj->size; + +#ifdef DEBUG + printf( "liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size ); + + printf( "liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))) ); + FLUSH(); +#endif + + + return maj; +} + + +void *PREFIX(malloc)(size_t req_size) { + int startedBet = 0; + unsigned long long bestSize = 0; + void *p = NULL; + uintptr_t diff; + struct liballoc_major *maj; + struct liballoc_minor *min; + struct liballoc_minor *new_min; + unsigned long size = req_size; + + // For alignment, we adjust size so there's enough space to align. + if (ALIGNMENT > 1) { + size += ALIGNMENT + ALIGN_INFO; + } + // So, ideally, we really want an alignment of 0 or 1 in order + // to save space. + + liballoc_lock(); + + if (size == 0) { + l_warningCount += 1; +#if defined DEBUG || defined INFO + printf( "liballoc: WARNING: alloc( 0 ) called from %x\n", + __builtin_return_address(0) ); + FLUSH(); +#endif + liballoc_unlock(); + return PREFIX(malloc)(1); + } + + + if (l_memRoot == NULL) { +#if defined DEBUG || defined INFO +#ifdef DEBUG + printf( "liballoc: initialization of liballoc " VERSION "\n" ); +#endif + atexit( liballoc_dump ); + FLUSH(); +#endif + + // This is the first time we are being used. + l_memRoot = allocate_new_page(size); + if (l_memRoot == NULL) { + liballoc_unlock(); +#ifdef DEBUG + printf( "liballoc: initial l_memRoot initialization failed\n", p); + FLUSH(); +#endif + return NULL; + } + +#ifdef DEBUG + printf( "liballoc: set up first memory major %x\n", l_memRoot ); + FLUSH(); +#endif + } + + +#ifdef DEBUG + printf( "liballoc: %x PREFIX(malloc)( %i ): ", + __builtin_return_address(0), + size ); + FLUSH(); +#endif + + // Now we need to bounce through every major and find enough space.... + + maj = l_memRoot; + startedBet = 0; + + // Start at the best bet.... + if (l_bestBet != NULL) { + bestSize = l_bestBet->size - l_bestBet->usage; + + if (bestSize > (size + sizeof(struct liballoc_minor))) { + maj = l_bestBet; + startedBet = 1; + } + } + + while (maj != NULL) { + diff = maj->size - maj->usage; + // free memory in the block + + if (bestSize < diff) { + // Hmm.. this one has more memory then our bestBet. Remember! + l_bestBet = maj; + bestSize = diff; + } + + +#ifdef USE_CASE1 + + // CASE 1: There is not enough space in this major block. + if (diff < (size + sizeof(struct liballoc_minor))) { +#ifdef DEBUG + printf( "CASE 1: Insufficient space in block %x\n", maj); + FLUSH(); +#endif + + // Another major block next to this one? + if (maj->next != NULL) { + maj = maj->next; // Hop to that one. + continue; + } + + if (startedBet == 1) // If we started at the best bet, + { // let's start all over again. + maj = l_memRoot; + startedBet = 0; + continue; + } + + // Create a new major block next to this one and... + maj->next = allocate_new_page(size); // next one will be okay. + if (maj->next == NULL) break; // no more memory. + maj->next->prev = maj; + maj = maj->next; + + // .. fall through to CASE 2 .. + } + +#endif + +#ifdef USE_CASE2 + + // CASE 2: It's a brand new block. + if (maj->first == NULL) { + maj->first = (struct liballoc_minor *) ((uintptr_t) maj + sizeof(struct liballoc_major)); + + + maj->first->magic = LIBALLOC_MAGIC; + maj->first->prev = NULL; + maj->first->next = NULL; + maj->first->block = maj; + maj->first->size = size; + maj->first->req_size = req_size; + maj->usage += size + sizeof(struct liballoc_minor); + + + l_inuse += size; + + + p = (void *) ((uintptr_t) (maj->first) + sizeof(struct liballoc_minor)); + + ALIGN(p); + +#ifdef DEBUG + printf( "CASE 2: returning %x\n", p); + FLUSH(); +#endif + liballoc_unlock(); // release the lock + return p; + } + +#endif + +#ifdef USE_CASE3 + + // CASE 3: Block in use and enough space at the start of the block. + diff = (uintptr_t) (maj->first); + diff -= (uintptr_t) maj; + diff -= sizeof(struct liballoc_major); + + if (diff >= (size + sizeof(struct liballoc_minor))) { + // Yes, space in front. Squeeze in. + maj->first->prev = (struct liballoc_minor *) ((uintptr_t) maj + sizeof(struct liballoc_major)); + maj->first->prev->next = maj->first; + maj->first = maj->first->prev; + + maj->first->magic = LIBALLOC_MAGIC; + maj->first->prev = NULL; + maj->first->block = maj; + maj->first->size = size; + maj->first->req_size = req_size; + maj->usage += size + sizeof(struct liballoc_minor); + + l_inuse += size; + + p = (void *) ((uintptr_t) (maj->first) + sizeof(struct liballoc_minor)); + ALIGN(p); + +#ifdef DEBUG + printf( "CASE 3: returning %x\n", p); + FLUSH(); +#endif + liballoc_unlock(); // release the lock + return p; + } + +#endif + + +#ifdef USE_CASE4 + + // CASE 4: There is enough space in this block. But is it contiguous? + min = maj->first; + + // Looping within the block now... + while (min != NULL) { + // CASE 4.1: End of minors in a block. Space from last and end? + if (min->next == NULL) { + // the rest of this block is free... is it big enough? + diff = (uintptr_t) (maj) + maj->size; + diff -= (uintptr_t) min; + diff -= sizeof(struct liballoc_minor); + diff -= min->size; + // minus already existing usage.. + + if (diff >= (size + sizeof(struct liballoc_minor))) { + // yay.... + min->next = (struct liballoc_minor *) ((uintptr_t) min + sizeof(struct liballoc_minor) + min->size); + min->next->prev = min; + min = min->next; + min->next = NULL; + min->magic = LIBALLOC_MAGIC; + min->block = maj; + min->size = size; + min->req_size = req_size; + maj->usage += size + sizeof(struct liballoc_minor); + + l_inuse += size; + + p = (void *) ((uintptr_t) min + sizeof(struct liballoc_minor)); + ALIGN(p); + +#ifdef DEBUG + printf( "CASE 4.1: returning %x\n", p); + FLUSH(); +#endif + liballoc_unlock(); // release the lock + return p; + } + } + + + + // CASE 4.2: Is there space between two minors? + if (min->next != NULL) { + // is the difference between here and next big enough? + diff = (uintptr_t) (min->next); + diff -= (uintptr_t) min; + diff -= sizeof(struct liballoc_minor); + diff -= min->size; + // minus our existing usage. + + if (diff >= (size + sizeof(struct liballoc_minor))) { + // yay...... + new_min = (struct liballoc_minor *) ((uintptr_t) min + sizeof(struct liballoc_minor) + min->size); + + new_min->magic = LIBALLOC_MAGIC; + new_min->next = min->next; + new_min->prev = min; + new_min->size = size; + new_min->req_size = req_size; + new_min->block = maj; + min->next->prev = new_min; + min->next = new_min; + maj->usage += size + sizeof(struct liballoc_minor); + + l_inuse += size; + + p = (void *) ((uintptr_t) new_min + sizeof(struct liballoc_minor)); + ALIGN(p); + + +#ifdef DEBUG + printf( "CASE 4.2: returning %x\n", p); + FLUSH(); +#endif + + liballoc_unlock(); // release the lock + return p; + } + } // min->next != NULL + + min = min->next; + } // while min != NULL ... + + +#endif + +#ifdef USE_CASE5 + + // CASE 5: Block full! Ensure next block and loop. + if (maj->next == NULL) { +#ifdef DEBUG + printf( "CASE 5: block full\n"); + FLUSH(); +#endif + + if (startedBet == 1) { + maj = l_memRoot; + startedBet = 0; + continue; + } + + // we've run out. we need more... + maj->next = allocate_new_page(size); // next one guaranteed to be okay + if (maj->next == NULL) break; // uh oh, no more memory..... + maj->next->prev = maj; + + } + +#endif + + maj = maj->next; + } // while (maj != NULL) + + + + liballoc_unlock(); // release the lock + +#ifdef DEBUG + printf( "All cases exhausted. No memory available.\n"); + FLUSH(); +#endif +#if defined DEBUG || defined INFO + printf( "liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size); + liballoc_dump(); + FLUSH(); +#endif + return NULL; +} + + +void PREFIX(free)(void *ptr) { + struct liballoc_minor *min; + struct liballoc_major *maj; + + if (ptr == NULL) { + l_warningCount += 1; +#if defined DEBUG || defined INFO + printf( "liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n", + __builtin_return_address(0) ); + FLUSH(); +#endif + return; + } + + UNALIGN(ptr); + + liballoc_lock(); // lockit + + + min = (struct liballoc_minor *) ((uintptr_t) ptr - sizeof(struct liballoc_minor)); + + + if (min->magic != LIBALLOC_MAGIC) { + l_errorCount += 1; + + // Check for overrun errors. For all bytes of LIBALLOC_MAGIC + if ( + ((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || + ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || + ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)) + ) { + l_possibleOverruns += 1; +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", + min->magic, + LIBALLOC_MAGIC ); + FLUSH(); +#endif + } + + + if (min->magic == LIBALLOC_DEAD) { +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", + ptr, + __builtin_return_address(0) ); + FLUSH(); +#endif + } else { +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", + ptr, + __builtin_return_address(0) ); + FLUSH(); +#endif + } + + // being lied to... + liballoc_unlock(); // release the lock + return; + } + +#ifdef DEBUG + printf( "liballoc: %x PREFIX(free)( %x ): ", + __builtin_return_address( 0 ), + ptr ); + FLUSH(); +#endif + + + maj = min->block; + + l_inuse -= min->size; + + maj->usage -= (min->size + sizeof(struct liballoc_minor)); + min->magic = LIBALLOC_DEAD; // No mojo. + + if (min->next != NULL) min->next->prev = min->prev; + if (min->prev != NULL) min->prev->next = min->next; + + if (min->prev == NULL) maj->first = min->next; + // Might empty the block. This was the first + // minor. + + + // We need to clean up after the majors now.... + + if (maj->first == NULL) // Block completely unused. + { + if (l_memRoot == maj) l_memRoot = maj->next; + if (l_bestBet == maj) l_bestBet = NULL; + if (maj->prev != NULL) maj->prev->next = maj->next; + if (maj->next != NULL) maj->next->prev = maj->prev; + l_allocated -= maj->size; + + liballoc_free(maj, maj->pages); + } else { + if (l_bestBet != NULL) { + int bestSize = l_bestBet->size - l_bestBet->usage; + int majSize = maj->size - maj->usage; + + if (majSize > bestSize) l_bestBet = maj; + } + + } + + +#ifdef DEBUG + printf( "OK\n"); + FLUSH(); +#endif + + liballoc_unlock(); // release the lock +} + + +void *PREFIX(calloc)(size_t nobj, size_t size) { + int real_size; + void *p; + + real_size = nobj * size; + + p = PREFIX(malloc)(real_size); + + liballoc_memset(p, 0, real_size); + + return p; +} + + +void *PREFIX(realloc)(void *p, size_t size) { + void *ptr; + struct liballoc_minor *min; + unsigned int real_size; + + // Honour the case of size == 0 => free old and return NULL + if (size == 0) { + PREFIX(free)(p); + return NULL; + } + + // In the case of a NULL pointer, return a simple malloc. + if (p == NULL) return PREFIX(malloc)(size); + + // Unalign the pointer if required. + ptr = p; + UNALIGN(ptr); + + liballoc_lock(); // lockit + + min = (struct liballoc_minor *) ((uintptr_t) ptr - sizeof(struct liballoc_minor)); + + // Ensure it is a valid structure. + if (min->magic != LIBALLOC_MAGIC) { + l_errorCount += 1; + + // Check for overrun errors. For all bytes of LIBALLOC_MAGIC + if ( + ((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) || + ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) || + ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)) + ) { + l_possibleOverruns += 1; +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n", + min->magic, + LIBALLOC_MAGIC ); + FLUSH(); +#endif + } + + + if (min->magic == LIBALLOC_DEAD) { +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n", + ptr, + __builtin_return_address(0) ); + FLUSH(); +#endif + } else { +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n", + ptr, + __builtin_return_address(0) ); + FLUSH(); +#endif + } + + // being lied to... + liballoc_unlock(); // release the lock + return NULL; + } + + // Definitely a memory block. + + real_size = min->req_size; + + if (real_size >= size) { + min->req_size = size; + liballoc_unlock(); + return p; + } + + liballoc_unlock(); + + // If we got here then we're reallocating to a block bigger than us. + ptr = PREFIX(malloc)(size); // We need to allocate new memory + liballoc_memcpy(ptr, p, real_size); + PREFIX(free)(p); + + return ptr; +} diff --git a/yak-kernel/src/rt/core/mem/malloc.c b/yak-kernel/src/rt/core/mem/malloc.c new file mode 100644 index 0000000..08aa0e9 --- /dev/null +++ b/yak-kernel/src/rt/core/mem/malloc.c @@ -0,0 +1,39 @@ +// +// Created by rick on 29-3-24. +// + +#include +#include "yak/rt/panic.h" + +#define PREALLOC_PAGES 16 +#define PAGE_SIZE 4096 + +uint8_t heap_initial[PAGE_SIZE * PREALLOC_PAGES]; +size_t pagesInUse = 0; + + +int liballoc_lock() { + return 0; // todo +} + +int liballoc_unlock() { + return 0; // todo +} + +void *liballoc_alloc(size_t size) { + if (size > (PREALLOC_PAGES - pagesInUse)) { + return NULL; + } + void *heap = &heap_initial[pagesInUse * PAGE_SIZE]; + pagesInUse += size; + return heap; +} + +int liballoc_free(void *page, size_t size) { + if (page == heap_initial && size == PREALLOC_PAGES) { + // freeing the entire initial heap + pagesInUse = 0; + return 0; + } + panic("Can't free malloc"); +} \ No newline at end of file diff --git a/yak-kernel/src/rt/core/mem/memmap.c b/yak-kernel/src/rt/core/mem/memmap.c new file mode 100644 index 0000000..cb6fa6a --- /dev/null +++ b/yak-kernel/src/rt/core/mem/memmap.c @@ -0,0 +1,41 @@ +// +// Created by rick on 4-10-23. +// + +#include +#include +#include + +#include + +#define MEMMAP_ENTRIES 64 + + +typedef struct { + uintptr_t address; + size_t length; + uint8_t type; +} mmap_entry; +mmap_entry memmap[MEMMAP_ENTRIES] = {0}; + +void memmap_put_entry(uintptr_t address, size_t length, uint8_t type) { + if (type == MMAP_TYPE_UNDEFINED || type > MMAP_LAST_TYPE) { + panic("Bad memory type"); + } + if ((address & 0xFFF) != 0) { + printf("MMap entry %8lx is not page aligned\n", address); + } + if (length % 4096 != 0) { + printf("MMap entry %8lx not a full page %8lx\n", address, length); + } + + for (int i = 0; i < MEMMAP_ENTRIES; ++i) { + if (memmap[i].type == 0) { + memmap[i].address = address; + memmap[i].length = length; + memmap[i].type = type; + return; + } + } + panic("No space left in memory map"); +} \ No newline at end of file diff --git a/yak-kernel/src/ulibc/temp.c b/yak-kernel/src/ulibc/temp.c index c8632ac..f9e35d5 100644 --- a/yak-kernel/src/ulibc/temp.c +++ b/yak-kernel/src/ulibc/temp.c @@ -3,15 +3,4 @@ // // TODO temporary to get compiling -#include -#include - -void* malloc(size_t size) { - panic("Not Yet Implemented"); -} - -void free(void* ptr) { - panic("Not Yet Implemented"); -} - int errno = 0; \ No newline at end of file