Update files

This commit is contained in:
Alex
2022-10-10 23:29:39 +03:00
parent 32b44a50d4
commit 4b6683823f
39 changed files with 2133 additions and 26 deletions

28
Library/Bitmap.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <bitmap.hpp>
bool Bitmap::operator[](uint64_t index) { return Get(index); }
bool Bitmap::Get(uint64_t index)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
}
bool Bitmap::Set(uint64_t index, bool value)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
}

442
Library/String.c Normal file
View File

@ -0,0 +1,442 @@
#include <string.h>
#include <types.h>
// TODO: Replace mem* with assembly code
/* Some of the functions are from musl library */
/* https://www.musl-libc.org/ */
/*
Copyright © 2005-2020 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
void *memcpy(void *dest, const void *src, size_t n)
{
unsigned char *d = dest;
const unsigned char *s = src;
#ifdef __GNUC__
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LS >>
#define RS <<
#else
#define LS <<
#define RS >>
#endif
typedef uint32_t __attribute__((__may_alias__)) u32;
uint32_t w, x;
for (; (uintptr_t)s % 4 && n; n--)
*d++ = *s++;
if ((uintptr_t)d % 4 == 0)
{
for (; n >= 16; s += 16, d += 16, n -= 16)
{
*(u32 *)(d + 0) = *(u32 *)(s + 0);
*(u32 *)(d + 4) = *(u32 *)(s + 4);
*(u32 *)(d + 8) = *(u32 *)(s + 8);
*(u32 *)(d + 12) = *(u32 *)(s + 12);
}
if (n & 8)
{
*(u32 *)(d + 0) = *(u32 *)(s + 0);
*(u32 *)(d + 4) = *(u32 *)(s + 4);
d += 8;
s += 8;
}
if (n & 4)
{
*(u32 *)(d + 0) = *(u32 *)(s + 0);
d += 4;
s += 4;
}
if (n & 2)
{
*d++ = *s++;
*d++ = *s++;
}
if (n & 1)
{
*d = *s;
}
return dest;
}
if (n >= 32)
switch ((uintptr_t)d % 4)
{
case 1:
w = *(u32 *)s;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
n -= 3;
for (; n >= 17; s += 16, d += 16, n -= 16)
{
x = *(u32 *)(s + 1);
*(u32 *)(d + 0) = (w LS 24) | (x RS 8);
w = *(u32 *)(s + 5);
*(u32 *)(d + 4) = (x LS 24) | (w RS 8);
x = *(u32 *)(s + 9);
*(u32 *)(d + 8) = (w LS 24) | (x RS 8);
w = *(u32 *)(s + 13);
*(u32 *)(d + 12) = (x LS 24) | (w RS 8);
}
break;
case 2:
w = *(u32 *)s;
*d++ = *s++;
*d++ = *s++;
n -= 2;
for (; n >= 18; s += 16, d += 16, n -= 16)
{
x = *(u32 *)(s + 2);
*(u32 *)(d + 0) = (w LS 16) | (x RS 16);
w = *(u32 *)(s + 6);
*(u32 *)(d + 4) = (x LS 16) | (w RS 16);
x = *(u32 *)(s + 10);
*(u32 *)(d + 8) = (w LS 16) | (x RS 16);
w = *(u32 *)(s + 14);
*(u32 *)(d + 12) = (x LS 16) | (w RS 16);
}
break;
case 3:
w = *(u32 *)s;
*d++ = *s++;
n -= 1;
for (; n >= 19; s += 16, d += 16, n -= 16)
{
x = *(u32 *)(s + 3);
*(u32 *)(d + 0) = (w LS 8) | (x RS 24);
w = *(u32 *)(s + 7);
*(u32 *)(d + 4) = (x LS 8) | (w RS 24);
x = *(u32 *)(s + 11);
*(u32 *)(d + 8) = (w LS 8) | (x RS 24);
w = *(u32 *)(s + 15);
*(u32 *)(d + 12) = (x LS 8) | (w RS 24);
}
break;
}
if (n & 16)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 8)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 4)
{
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
}
if (n & 2)
{
*d++ = *s++;
*d++ = *s++;
}
if (n & 1)
{
*d = *s;
}
return dest;
#endif
for (; n; n--)
*d++ = *s++;
return dest;
}
void *memset(void *dest, int c, size_t n)
{
unsigned char *s = dest;
size_t k;
if (!n)
return dest;
s[0] = c;
s[n - 1] = c;
if (n <= 2)
return dest;
s[1] = c;
s[2] = c;
s[n - 2] = c;
s[n - 3] = c;
if (n <= 6)
return dest;
s[3] = c;
s[n - 4] = c;
if (n <= 8)
return dest;
k = -(uintptr_t)s & 3;
s += k;
n -= k;
n &= -4;
#ifdef __GNUC__
typedef uint32_t __attribute__((__may_alias__)) u32;
typedef uint64_t __attribute__((__may_alias__)) u64;
u32 c32 = ((u32)-1) / 255 * (unsigned char)c;
*(u32 *)(s + 0) = c32;
*(u32 *)(s + n - 4) = c32;
if (n <= 8)
return dest;
*(u32 *)(s + 4) = c32;
*(u32 *)(s + 8) = c32;
*(u32 *)(s + n - 12) = c32;
*(u32 *)(s + n - 8) = c32;
if (n <= 24)
return dest;
*(u32 *)(s + 12) = c32;
*(u32 *)(s + 16) = c32;
*(u32 *)(s + 20) = c32;
*(u32 *)(s + 24) = c32;
*(u32 *)(s + n - 28) = c32;
*(u32 *)(s + n - 24) = c32;
*(u32 *)(s + n - 20) = c32;
*(u32 *)(s + n - 16) = c32;
k = 24 + ((uintptr_t)s & 4);
s += k;
n -= k;
u64 c64 = c32 | ((u64)c32 << 32);
for (; n >= 32; n -= 32, s += 32)
{
*(u64 *)(s + 0) = c64;
*(u64 *)(s + 8) = c64;
*(u64 *)(s + 16) = c64;
*(u64 *)(s + 24) = c64;
}
#else
for (; n; n--, s++)
*s = c;
#endif
return dest;
}
void *memmove(void *dest, const void *src, size_t n)
{
#ifdef __GNUC__
typedef __attribute__((__may_alias__)) size_t WT;
#define WS (sizeof(WT))
#endif
char *d = dest;
const char *s = src;
if (d == s)
return d;
if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n)
return memcpy(d, s, n);
if (d < s)
{
#ifdef __GNUC__
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
{
while ((uintptr_t)d % WS)
{
if (!n--)
return dest;
*d++ = *s++;
}
for (; n >= WS; n -= WS, d += WS, s += WS)
*(WT *)d = *(WT *)s;
}
#endif
for (; n; n--)
*d++ = *s++;
}
else
{
#ifdef __GNUC__
if ((uintptr_t)s % WS == (uintptr_t)d % WS)
{
while ((uintptr_t)(d + n) % WS)
{
if (!n--)
return dest;
d[n] = s[n];
}
while (n >= WS)
n -= WS, *(WT *)(d + n) = *(WT *)(s + n);
}
#endif
while (n)
n--, d[n] = s[n];
}
return dest;
}
int memcmp(const void *vl, const void *vr, size_t n)
{
const unsigned char *l = vl, *r = vr;
for (; n && *l == *r; n--, l++, r++)
;
return n ? *l - *r : 0;
}
int strncmp(const char *s1, const char *s2, size_t n)
{
for (size_t i = 0; i < n; i++)
{
char c1 = s1[i], c2 = s2[i];
if (c1 != c2)
return c1 - c2;
if (!c1)
return 0;
}
return 0;
}
long unsigned strlen(const char s[])
{
long unsigned i = 0;
while (s[i] != '\0')
++i;
return i;
}
char *strcat(char *destination, const char *source)
{
if ((destination == NULL) && (source == NULL))
return NULL;
char *start = destination;
while (*start != '\0')
{
start++;
}
while (*source != '\0')
{
*start++ = *source++;
}
*start = '\0';
return destination;
}
char *strcpy(char *destination, const char *source)
{
if (destination == NULL)
return NULL;
char *ptr = destination;
while (*source != '\0')
{
*destination = *source;
destination++;
source++;
}
*destination = '\0';
return ptr;
}
char *strncpy(char *destination, const char *source, unsigned long num)
{
if (destination == NULL)
return NULL;
char *ptr = destination;
while (*source && num--)
{
*destination = *source;
destination++;
source++;
}
*destination = '\0';
return ptr;
}
int strcmp(const char *l, const char *r)
{
for (; *l == *r && *l; l++, r++)
;
return *(unsigned char *)l - *(unsigned char *)r;
}
char *strstr(const char *haystack, const char *needle)
{
const char *a = haystack, *b = needle;
while (1)
{
if (!*b)
return (char *)haystack;
if (!*a)
return NULL;
if (*a++ != *b++)
{
a = ++haystack;
b = needle;
}
}
}
int isdigit(int c)
{
return c >= '0' && c <= '9';
}
int isspace(int c)
{
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v';
}
int isempty(char *str)
{
if (strlen(str) == 0)
return 1;
while (*str != '\0')
{
if (!isspace(*str))
return 0;
str++;
}
return 1;
}

140
Library/cxxabi.cpp Normal file
View File

@ -0,0 +1,140 @@
#include <types.h>
#include <debug.h>
// TODO: complete implementation for everything
// TODO: https://wiki.osdev.org/C%2B%2B
#define ATEXIT_MAX_FUNCS 128
typedef unsigned uarch_t;
struct atexit_func_entry_t
{
/*
* Each member is at least 4 bytes large. Such that each entry is 12bytes.
* 128 * 12 = 1.5KB exact.
**/
void (*destructor_func)(void *);
void *obj_ptr;
void *dso_handle;
};
typedef enum
{
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
struct _Unwind_Context;
typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
typedef unsigned _Unwind_Word __attribute__((__mode__(__unwind_word__)));
typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, struct _Unwind_Exception *);
typedef int _Unwind_Action;
struct _Unwind_Exception
{
_Unwind_Exception_Class exception_class;
_Unwind_Exception_Cleanup_Fn exception_cleanup;
#if !defined(__USING_SJLJ_EXCEPTIONS__) && defined(__SEH__)
_Unwind_Word private_[6];
#else
_Unwind_Word private_1;
_Unwind_Word private_2;
#endif
} __attribute__((__aligned__));
extern void *__dso_handle = 0;
atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS];
uarch_t __atexit_func_count = 0;
extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso)
{
fixme("__cxa_atexit( %p %p %p ) triggered.", f, objptr, dso);
if (__atexit_func_count >= ATEXIT_MAX_FUNCS)
return -1;
__atexit_funcs[__atexit_func_count].destructor_func = f;
__atexit_funcs[__atexit_func_count].obj_ptr = objptr;
__atexit_funcs[__atexit_func_count].dso_handle = dso;
__atexit_func_count++;
return 0;
}
extern "C" void __cxa_finalize(void *f)
{
fixme("__cxa_finalize( %p ) triggered.", f);
uarch_t i = __atexit_func_count;
if (!f)
{
while (i--)
if (__atexit_funcs[i].destructor_func)
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
return;
}
while (i--)
if (__atexit_funcs[i].destructor_func == f)
{
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__atexit_funcs[i].destructor_func = 0;
}
}
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context)
{
fixme("__gxx_personality_v0( %d %p %p %p %p ) triggered.", version, actions, exception_class, ue_header, context);
return _URC_NO_REASON;
}
extern "C" void _Unwind_Resume(struct _Unwind_Exception *exc) { fixme("_Unwind_Resume( %p ) triggered.", exc); }
extern "C" void *__cxa_allocate_exception(uint64_t thrown_size) throw()
{
fixme("__cxa_allocate_exception( %#llu ) triggered.", thrown_size);
return (void *)0;
}
extern "C" void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *)) { fixme("__cxa_throw( %p %p %p ) triggered.", thrown_object, tinfo, dest); }
extern "C" void __cxa_rethrow() { fixme("__cxa_rethrow() triggered."); }
extern "C" void __cxa_pure_virtual() { fixme("__cxa_pure_virtual() triggered."); }
extern "C" void __cxa_throw_bad_array_new_length() { fixme("__cxa_throw_bad_array_new_length() triggered."); }
extern "C" void __cxa_free_exception(void *thrown_exception) { fixme("__cxa_free_exception( %p ) triggered.", thrown_exception); }
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
extern "C" void *__cxa_begin_catch(void *e) throw()
#else
extern "C" void *__cxa_begin_catch(void *e)
#endif
{
fixme("__cxa_begin_catch( %p ) triggered.", e);
return (void *)0;
}
extern "C" void __cxa_end_catch() { fixme("__cxa_end_catch() triggered."); }
__extension__ typedef int __guard __attribute__((mode(__DI__)));
extern "C" int __cxa_guard_acquire(__guard *g)
{
fixme("__cxa_guard_acquire( %p ) triggered.", g);
return !*(char *)(g);
}
extern "C" void __cxa_guard_release(__guard *g)
{
fixme("__cxa_guard_release( %p ) triggered.", g);
*(char *)g = 1;
}
extern "C" void __cxa_guard_abort(__guard *g) { fixme("__cxa_guard_abort( %p ) triggered.", g); }

790
Library/liballoc_1_1.c Normal file
View File

@ -0,0 +1,790 @@
#include "liballoc_1_1.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
// #define LIBALLOCDEBUG 1
#define LIBALLOCINFO 1
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
// #include <stdio.h>
// #include <stdlib.h>
#include <debug.h>
// #define FLUSH() fflush(stdout)
#define FLUSH()
#define atexit(x)
#define printf(m, ...) trace(m, ##__VA_ARGS__)
#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 LIBALLOCDEBUG || defined LIBALLOCINFO
static void liballoc_dump()
{
#ifdef LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG || defined LIBALLOCINFO
#ifdef LIBALLOCDEBUG
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 LIBALLOCDEBUG
printf("liballoc: initial l_memRoot initialization failed\n", p);
FLUSH();
#endif
return NULL;
}
#ifdef LIBALLOCDEBUG
printf("liballoc: set up first memory major %x\n", l_memRoot);
FLUSH();
#endif
}
#ifdef LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
printf("All cases exhausted. No memory available.\n");
FLUSH();
#endif
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
else
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG
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 LIBALLOCDEBUG || defined LIBALLOCINFO
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 LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
else
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
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;
}

74
Library/liballoc_1_1.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef _LIBALLOC_H
#define _LIBALLOC_H
#include <types.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) kliballoc_##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

14
Library/liballocimpl.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <types.h>
#include <lock.hpp>
#include <memory.hpp>
NEWLOCK(liballocLock);
EXTERNC int liballoc_lock() { return liballocLock.Lock(); }
EXTERNC int liballoc_unlock() { return liballocLock.Unlock(); }
EXTERNC void *liballoc_alloc(size_t Pages) { return KernelAllocator.RequestPages(Pages); }
EXTERNC int liballoc_free(void *Address, size_t Pages)
{
KernelAllocator.FreePages(Address, Pages);
return 0;
}

1591
Library/printf.c Normal file

File diff suppressed because it is too large Load Diff