diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index da0f175..c24fede 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -38,7 +38,7 @@ char getc() { KeyEvent *event = get_next_event(); char retval = 0; if (event == NULL) { - goto _getc_end; + goto _getc_end_nofree; } if (event->is_release) { goto _getc_end; @@ -53,6 +53,7 @@ char getc() { } _getc_end: free_event(event); + _getc_end_nofree: if (retval != 0) { return retval; } diff --git a/kernel/kernel.c b/kernel/kernel.c index 97cc0d0..586e407 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -29,7 +29,7 @@ void init_mmap(multiboot_info_t *multiboot_info) { if (multiboot_info->flags & (1 << 6)) { mmap_init_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr, multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry)); - malloc_init(); +// malloc_init(); // todo fallback on other mechanisms? } else { k_panics("mmap invalid!\n"); diff --git a/kernel/libc/kprintf.c b/kernel/libc/kprintf.c index 133824a..9e73f6c 100644 --- a/kernel/libc/kprintf.c +++ b/kernel/libc/kprintf.c @@ -58,6 +58,7 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) { case 'x': print_int((uint32_t) va_arg(args, uint32_t), arg_width, buf, &ptr, 16); break; + case 'i': case 'd': print_int((uint32_t) va_arg(args, uint32_t), arg_width, buf, &ptr, 10); break; diff --git a/kernel/libc/ringqueue.c b/kernel/libc/ringqueue.c index ee75408..dd454f4 100644 --- a/kernel/libc/ringqueue.c +++ b/kernel/libc/ringqueue.c @@ -25,7 +25,7 @@ void *create_buffer(int count, int object_size) { buffer->count = count; buffer->read_pos = 0; buffer->write_pos = 0; - buffer->mem = malloc(count * object_size); + buffer->mem = calloc(object_size, count); if (buffer->mem == NULL) { free(buffer); return NULL; diff --git a/kernel/mem/malloc.c b/kernel/mem/malloc.c index 4047257..92b2e9b 100644 --- a/kernel/mem/malloc.c +++ b/kernel/mem/malloc.c @@ -7,84 +7,824 @@ #include "malloc.h" #include "pmm.h" -#define MALLOC_TYPE_FREE 0 -#define MALLOC_TYPE_USED 1 +// retrieved from https://github.com/blanham/liballoc -int malloc_entries = 0; -int malloc_used = 0; - -typedef struct malloc_map { - struct malloc_map *next; - struct malloc_map *prev; - uint32_t size; - int type; -} malloc_map; - -malloc_map *first_malloc_entry; - -void malloc_init() { - first_malloc_entry = pmm_get_pages(16); - first_malloc_entry->next = first_malloc_entry; - first_malloc_entry->prev = first_malloc_entry; - first_malloc_entry->size = PAGE_SIZE * 16; - first_malloc_entry->type = MALLOC_TYPE_FREE; - malloc_entries++; -} - -void split_malloc_map(malloc_map *entry, unsigned int size) { - malloc_entries++; - malloc_map *new_entry = entry + sizeof(malloc_map) + size; - new_entry->size = entry->size - size - sizeof(malloc_map); - new_entry->next = entry->next; - new_entry->prev = entry; - new_entry->type = MALLOC_TYPE_FREE; - entry->next->prev = new_entry; - entry->next = new_entry; - entry->size = size; -} - -void *malloc(size_t size) { - // todo replace this horrible mess! - // this lacks any page alignment and what so ever - void* result = NULL; +/** 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. + */ +int liballoc_lock() { task_lock_acquire(); - malloc_map *current_map = first_malloc_entry; - // iterate through maps - do { - if (current_map->type == MALLOC_TYPE_USED) { - goto malloc_find_next; - } - if ((unsigned int) current_map->size < size) { - goto malloc_find_next; - } - if ((unsigned int) current_map->size > (size + sizeof(malloc_map))) { - // big enough to split - split_malloc_map(current_map, size); - } - malloc_used++; - current_map->type = MALLOC_TYPE_USED; - result = ((void *) current_map) + sizeof(malloc_map); - break; - - malloc_find_next: - current_map = current_map->next; - } while (current_map != first_malloc_entry); - task_lock_free(); - return result; + return 0; } -void free(void *mem) { - if (mem == NULL) { - return; - } - malloc_used--; - malloc_map *map = (mem - sizeof(malloc_map)); - map->type = MALLOC_TYPE_FREE; +/** 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. + */ +int liballoc_unlock() { + task_lock_free(); + return 0; +} + +/** 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. + */ +void *liballoc_alloc(size_t size) { + return pmm_get_pages(size); +} + +/** 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. + */ +int liballoc_free(void *addr, size_t size) { + pmm_free_pages(addr, size); + return 0; +} + +/** 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 +// todo support debug info +//#include +//#include + +//#define FLUSH() fflush( stdout ) +#define FLUSH() ; + +#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. }; -void print_malloc_info() { - printf("Malloc avail entries: %d\n" - "Malloc used entries: %d\n", malloc_entries, malloc_used); +/** 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 = PAGE_SIZE; ///< 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 uint32_t l_allocated = 0; ///< Running total of allocated memory. +static uint32_t l_inuse = 0; ///< Running total of used memory. + + +static uint32_t l_warningCount = 0; ///< Number of warnings encountered +static uint32_t l_errorCount = 0; ///< Number of actual errors +static uint32_t 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 *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 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 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: malloc( %i ) returning NULL.\n", size); + liballoc_dump(); + FLUSH(); +#endif + return NULL; +} + + +void 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: 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 free() attempt on %x from %x.\n", + ptr, + __builtin_return_address(0) ); + FLUSH(); +#endif + } else { +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: Bad 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 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 *calloc(size_t nobj, size_t size) { + int real_size; + void *p; + + real_size = nobj * size; + + p = malloc(real_size); + + liballoc_memset(p, 0, real_size); + + return p; +} + + +void *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) { + free(p); + return NULL; + } + + // In the case of a NULL pointer, return a simple malloc. + if (p == NULL) return 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 free() attempt on %x from %x.\n", + ptr, + __builtin_return_address(0) ); + FLUSH(); +#endif + } else { +#if defined DEBUG || defined INFO + printf( "liballoc: ERROR: Bad 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 = malloc(size); // We need to allocate new memory + liballoc_memcpy(ptr, p, real_size); + free(p); + + return ptr; +} + +void print_malloc_info() { +#if defined DEBUG || defined INFO + liballoc_dump(); +#else + printf("%d bytes allocated\n%d bytes in use\n%d warnings, %d errors, %d possible overruns\n", + l_allocated, l_inuse, l_warningCount, l_errorCount, l_possibleOverruns); +#endif +} diff --git a/kernel/mem/malloc.h b/kernel/mem/malloc.h index eb7e3ee..3099835 100644 --- a/kernel/mem/malloc.h +++ b/kernel/mem/malloc.h @@ -4,14 +4,17 @@ #ifndef NEW_KERNEL_MALLOC_H #define NEW_KERNEL_MALLOC_H +// retrieved from https://github.com/blanham/liballoc #include -void malloc_init(); +void *malloc(size_t); + +void *realloc(void *, size_t); + +void *calloc(size_t, size_t); + +void free(void *); void print_malloc_info(); -void *malloc(size_t size); - -void free(void *mem); - #endif //NEW_KERNEL_MALLOC_H