diff --git a/apps/Makefile b/apps/Makefile index 3a3d1bcc..a4814f10 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -6,7 +6,7 @@ APPS_BIN := $(APPS_DIR)/bin REAL_APPS := $(patsubst %, $(APPS_BIN)/%, $(APPS)) -CFLAGS := -Wall -Wextra -Werror -Os +CFLAGS := -Wall -Wextra -Werror $(APPS_BIN)/%: $(APPS_SRC)/%.c @mkdir -p $(@D) diff --git a/apps/src/init.c b/apps/src/init.c index 94aeb2eb..0f6ea89f 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -33,6 +33,13 @@ int main() sleep(2); + { + [[maybe_unused]] volatile int i; + char* variable = malloc(200); + *variable = 3; + free(variable); + } + println("Press any key to restart."); return 0; diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index 2d3bad59..295e89fb 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -10,6 +10,8 @@ #define SYS_rand 5 #define SYS_getversion 6 #define SYS_gettid 7 +#define SYS_mmap 8 +#define SYS_munmap 9 namespace Syscall { @@ -23,4 +25,6 @@ void sys_write(Context* context, const char* addr, size_t size); void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h, uint64_t col); void sys_rand(Context* context); void sys_getversion(Context* context, char* buffer, size_t max); -void sys_gettid(Context* context); \ No newline at end of file +void sys_gettid(Context* context); +void sys_mmap(Context* context, void* address, size_t size, int flags); +void sys_munmap(Context* context, void* address, size_t size); \ No newline at end of file diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 7059a1c0..7beeb902 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -23,6 +23,8 @@ void Syscall::entry(Context* context) case SYS_rand: sys_rand(context); break; case SYS_getversion: sys_getversion(context, (char*)context->rdi, context->rsi); break; case SYS_gettid: sys_gettid(context); break; + case SYS_mmap: sys_mmap(context, (void*)context->rdi, context->rsi, context->rdx); break; + case SYS_munmap: sys_munmap(context, (void*)context->rdi, context->rsi); break; default: context->rax = -1; break; } } \ No newline at end of file diff --git a/kernel/src/sys/mem.cpp b/kernel/src/sys/mem.cpp new file mode 100644 index 00000000..9eba7426 --- /dev/null +++ b/kernel/src/sys/mem.cpp @@ -0,0 +1,81 @@ +#define MODULE "mem" + +#include "interrupts/Context.h" +#include "log/Log.h" +#include "memory/MemoryManager.h" +#include "memory/VMM.h" +#include + +void sys_mmap(Context* context, void* address, size_t size, int flags) +{ + if (size < 4096) + { + kdbgln("sys_mmap: size too small"); + context->rax = 0; + return; + } + int real_flags = MAP_USER; + if (flags & MAP_READ_WRITE) real_flags |= MAP_READ_WRITE; + if (address) + { + kdbgln("sys_mmap: %ld pages at address %lx, %s", size / 4096, (uint64_t)address, + real_flags & MAP_READ_WRITE ? "rw" : "ro"); + if (kernelVMM.getPhysical((uint64_t)address) != (uint64_t)-1) // Address is already used. + { + kdbgln("attempt to mmap an already mapped address"); + context->rax = 0; + return; + } + uint64_t offset = (uint64_t)address % 4096; + void* result = MemoryManager::get_pages_at((uint64_t)address - offset, size / 4096, real_flags); + if (result) + { + kdbgln("mmap succeeded: %lx", (uint64_t)result); + context->rax = (uint64_t)result; + return; + } + else + { + kdbgln("mmap failed"); + context->rax = 0; + return; + } + } + kdbgln("sys_mmap: %ld pages at any address, %s", size / 4096, real_flags & MAP_READ_WRITE ? "rw" : "ro"); + void* result = MemoryManager::get_pages(size / 4096, real_flags); + if (result) + { + kdbgln("mmap succeeded: %lx", (uint64_t)result); + context->rax = (uint64_t)result; + return; + } + else + { + kdbgln("mmap failed"); + context->rax = 0; + return; + } +} + +void sys_munmap(Context* context, void* address, size_t size) +{ + kdbgln("sys_munmap: attempting to unmap %lx", (uint64_t)address); + if (!address) + { + kdbgln("munmap failed: attempted to unmap page 0"); + context->rax = -1; + return; + } + int flags = kernelVMM.getFlags((uint64_t)address); + if (!(flags & MAP_USER)) + { + kdbgln("munmap failed: attempted to unmap a kernel page"); + context->rax = -1; + return; + } + uint64_t offset = (uint64_t)address % 4096; + MemoryManager::release_pages((void*)((uint64_t)address - offset), size / 4096); + kdbgln("munmap succeeded"); + context->rax = 0; + return; +} \ No newline at end of file diff --git a/libs/libc/include/_/liballoc.h b/libs/libc/include/_/liballoc.h new file mode 100644 index 00000000..de56c1b4 --- /dev/null +++ b/libs/libc/include/_/liballoc.h @@ -0,0 +1,74 @@ +#ifndef _LIBALLOC_H +#define _LIBALLOC_H + +#include + +/** \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) 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 diff --git a/libs/libc/include/luna/syscall.h b/libs/libc/include/luna/syscall.h index 07977c44..241b0156 100644 --- a/libs/libc/include/luna/syscall.h +++ b/libs/libc/include/luna/syscall.h @@ -9,6 +9,8 @@ #define SYS_rand 5 #define SYS_getversion 6 #define SYS_gettid 7 +#define SYS_mmap 8 +#define SYS_munmap 9 #ifndef __want_syscalls #ifdef __cplusplus diff --git a/libs/libc/src/_/bindings.c b/libs/libc/src/_/bindings.c new file mode 100644 index 00000000..7794fcde --- /dev/null +++ b/libs/libc/src/_/bindings.c @@ -0,0 +1,27 @@ +#include +#include +#include + +int liballoc_lock() +{ + return 0; +} + +int liballoc_unlock() +{ + return 0; +} + +void* liballoc_alloc(size_t size) +{ + unsigned long int result = (unsigned long int)syscall(SYS_mmap, NULL, size * 4096, 1); + return (void*)result; +} + +int liballoc_free(void* address, size_t size) +{ + int result = syscall(SYS_munmap, address, size * 4096); + if (result < 0) return 1; + else + return 0; +} \ No newline at end of file diff --git a/libs/libc/src/_/liballoc.c b/libs/libc/src/_/liballoc.c new file mode 100644 index 00000000..e2db6403 --- /dev/null +++ b/libs/libc/src/_/liballoc.c @@ -0,0 +1,742 @@ +#include <_/liballoc.h> + +#include +#include + +/** 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/libs/libc/src/stdlib.cpp b/libs/libc/src/stdlib.cpp index 845ad10f..bae18830 100644 --- a/libs/libc/src/stdlib.cpp +++ b/libs/libc/src/stdlib.cpp @@ -29,16 +29,8 @@ extern "C" { NOT_IMPLEMENTED("atoi"); } - void free(void*) - { - NOT_IMPLEMENTED("free"); - } char* getenv(const char*) { NOT_IMPLEMENTED("getenv"); } - void* malloc(size_t) - { - NOT_IMPLEMENTED("malloc"); - } } \ No newline at end of file diff --git a/libs/libc/src/unistd.cpp b/libs/libc/src/unistd.cpp index cfdb9d58..2e3e6593 100644 --- a/libs/libc/src/unistd.cpp +++ b/libs/libc/src/unistd.cpp @@ -36,12 +36,20 @@ extern "C" case SYS_rand: result = __luna_syscall0(number); break; case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break; case SYS_write: + case SYS_munmap: case SYS_getversion: { arg arg0 = va_arg(ap, arg); arg arg1 = va_arg(ap, arg); result = __luna_syscall2(number, arg0, arg1); break; } + case SYS_mmap: { + arg arg0 = va_arg(ap, arg); + arg arg1 = va_arg(ap, arg); + arg arg2 = va_arg(ap, arg); + result = __luna_syscall3(number, arg0, arg1, arg2); + break; + } case SYS_paint: { arg arg0 = va_arg(ap, arg); arg arg1 = va_arg(ap, arg);