Add mmap and munmap syscalls, and thus, add malloc and free to libc!! (yet again, thanks to the wonderful liballoc)
This commit is contained in:
parent
ee31a3458d
commit
dae2ff8d50
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
@ -24,3 +26,5 @@ void sys_paint(Context* context, uint64_t x, uint64_t y, uint64_t w, uint64_t h,
|
||||
void sys_rand(Context* context);
|
||||
void sys_getversion(Context* context, char* buffer, size_t max);
|
||||
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);
|
@ -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;
|
||||
}
|
||||
}
|
81
kernel/src/sys/mem.cpp
Normal file
81
kernel/src/sys/mem.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#define MODULE "mem"
|
||||
|
||||
#include "interrupts/Context.h"
|
||||
#include "log/Log.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "memory/VMM.h"
|
||||
#include <stddef.h>
|
||||
|
||||
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;
|
||||
}
|
74
libs/libc/include/_/liballoc.h
Normal file
74
libs/libc/include/_/liballoc.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef _LIBALLOC_H
|
||||
#define _LIBALLOC_H
|
||||
|
||||
#include <stddef.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) 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
|
@ -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
|
||||
|
27
libs/libc/src/_/bindings.c
Normal file
27
libs/libc/src/_/bindings.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
742
libs/libc/src/_/liballoc.c
Normal file
742
libs/libc/src/_/liballoc.c
Normal file
@ -0,0 +1,742 @@
|
||||
#include <_/liballoc.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user