Add startings of new kernel-side library

Lainlib is libk. It is separate from Helix, which will become the 3D engine common to the kernel and the userspace.
This commit is contained in:
Curle 2020-08-31 21:44:54 +01:00
parent 61dbcc0dec
commit a915465fc1
Signed by: TheCurle
GPG Key ID: 5942F13718443F79
10 changed files with 776 additions and 0 deletions

View File

@ -0,0 +1,327 @@
/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; -*- */
/*
* This file is part of liblzg.
*
* Copyright (c) 2010-2018 Marcus Geelnard
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would
* be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef _LIBLZG_H_
#define _LIBLZG_H_
#ifdef __cplusplus
extern "C" {
#endif
#define LZG_VERSION "1.0.10" /**< @brief LZG library version string */
#define LZG_VERNUM 0x0100000a /**< @brief LZG library version number (strictly
incremental) */
#define LZG_VER_MAJOR 1 /**< @brief LZG library major version */
#define LZG_VER_MINOR 0 /**< @brief LZG library minor version */
#define LZG_VER_REVISION 10 /**< @brief LZG library revision */
/**
* @file
* @mainpage
*
* @section intro_sec Introduction
*
* liblzg is a minimal implementation of an LZ77 class compression library. The
* main characteristic of the library is that the decoding routine is very
* simple, fast and requires no extra memory (except for the encoded and decoded
* data buffers).
*
* @section funcs_sec Functions
*
* @li LZG_MaxEncodedSize() - Determine the maximum size of the encoded data for
* a given uncompressed buffer (worst case).
* @li LZG_InitEncoderConfig() - Set default encoder configuration.
* @li LZG_Encode() - Encode uncompressed data as LZG coded data.
* @li LZG_EncodeFull() - Same as LZG_Encode(), but using custom memory
* allocation.
* @li LZG_WorkMemSize() - Determine the amount of memory required for encoding
* (useful for LZG_EncodeFull()).
*
* @li LZG_DecodedSize() - Determine the size of the decoded data for a given
* LZG coded buffer.
* @li LZG_Decode() - Decode LZG coded data.
*
* @li LZG_Version() - Get the version of the LZG library.
* @li LZG_VersionString() - Get the version of the LZG library.
*
* @section compr_sec Compression
* Here is a simple example of compressing an uncompressed data buffer (given
* as buf/bufSize).
*
* @code
* unsigned char *encBuf;
* lzg_uint32_t encSize, maxEncSize;
*
* // Determine maximum size of compressed data
* maxEncSize = LZG_MaxEncodedSize(bufSize);
*
* // Allocate memory for the compressed data
* encBuf = (unsigned char*) malloc(maxEncSize);
* if (encBuf)
* {
* // Compress
* encSize = LZG_Encode(buf, bufSize, encBuf, maxEncSize, NULL);
* if (encSize)
* {
* // Compressed data is now in encBuf, use it...
* // ...
* }
* else
* fprintf(stderr, "Compression failed!\n");
*
* // Free memory when we're done with the compressed data
* free(encBuf);
* }
* else
* fprintf(stderr, "Out of memory!\n");
* @endcode
*
* @section decompr_sec Decompression
* Here is a simple example of decompressing a compressed data buffer (given
* as buf/bufSize).
*
* @code
* unsigned char *decBuf;
* lzg_uint32_t decSize;
*
* // Determine size of decompressed data
* decSize = LZG_DecodedSize(buf, bufSize);
* if (decSize)
* {
* // Allocate memory for the decompressed data
* decBuf = (unsigned char*) malloc(decSize);
* if (decBuf)
* {
* // Decompress
* decSize = LZG_Decode(buf, bufSize, decBuf, decSize);
* if (decSize)
* {
* // Uncompressed data is now in decBuf, use it...
* // ...
* }
* else
* printf("Decompression failed (bad data)!\n");
*
* // Free memory when we're done with the decompressed data
* free(decBuf);
* }
* else
* printf("Out of memory!\n");
* }
* else
* printf("Bad input data!\n");
* @endcode
*/
/* Basic types */
typedef int lzg_bool_t; /**< @brief Boolean (@ref LZG_TRUE/@ref LZG_FALSE) */
typedef int lzg_int32_t; /**< @brief Signed 32-bit integer */
typedef unsigned int lzg_uint32_t; /**< @brief Unsigned 32-bit integer */
#define LZG_FALSE 0 /**< @brief Boolean FALSE (see @ref lzg_bool_t) */
#define LZG_TRUE 1 /**< @brief Boolean TRUE (see @ref lzg_bool_t) */
/* Compression levels */
#define LZG_LEVEL_1 1 /**< @brief Lowest/fastest compression level */
#define LZG_LEVEL_2 2 /**< @brief Compression level 2 */
#define LZG_LEVEL_3 3 /**< @brief Compression level 3 */
#define LZG_LEVEL_4 4 /**< @brief Compression level 4 */
#define LZG_LEVEL_5 5 /**< @brief Medium compression level */
#define LZG_LEVEL_6 6 /**< @brief Compression level 6 */
#define LZG_LEVEL_7 7 /**< @brief Compression level 7 */
#define LZG_LEVEL_8 8 /**< @brief Compression level 8 */
#define LZG_LEVEL_9 9 /**< @brief Best/slowest compression level */
/** @brief Default compression level */
#define LZG_LEVEL_DEFAULT LZG_LEVEL_5
/**
* Progress callback function.
* @param[in] progress The current progress (0-100).
* @param[in] userdata User supplied data pointer.
*/
typedef void (*LZGPROGRESSFUN)(lzg_int32_t progress, void *userdata);
/** @brief LZG compression configuration parameters.
*
* This structure is used for passing configuration options to the LZG_Encode()
* function. Initialize this structure to default values with
* @ref LZG_InitEncoderConfig().
*/
typedef struct {
/** @brief Compression level (1-9).
For convenience, you can use the predefined constants
@ref LZG_LEVEL_1 (fast) to @ref LZG_LEVEL_9 (slow), or
@ref LZG_LEVEL_DEFAULT.
Default value: LZG_LEVEL_DEFAULT */
lzg_int32_t level;
/** @brief Use fast method (LZG_FALSE or LZG_TRUE).
Boolean flag that specifies whether or not to use a faster encoding
acceleration data structure, which requires more memory. When using the
fast method, the compression ratio is usually slightly improved.
Default value: LZG_TRUE */
lzg_bool_t fast;
/** @brief Encoding progress callback function.
This function will be called during compression to report progress
back to the caller (set this to NULL to disable progress
callback).
Default value: NULL */
LZGPROGRESSFUN progressfun;
/** @brief User data pointer for the progress callback function.
A user defined data pointer that can point to anything that the
progress callback function may need, such as an object reference
(this can set to NULL if the callback function does not need it).
Default value: NULL */
void *userdata;
} lzg_encoder_config_t;
/**
* Determine the maximum size of the encoded data for a given uncompressed
* buffer.
* @param[in] insize Size of the uncompressed buffer (number of bytes).
* @return Worst case (maximum) size of the encoded data.
*/
lzg_uint32_t LZG_MaxEncodedSize(lzg_uint32_t insize);
/**
* Initialize an encoder configuration object.
* @param[out] config Configuration object.
*/
void LZG_InitEncoderConfig(lzg_encoder_config_t *config);
/**
* Determine the amount of memory required for encoding.
* @param[in] config Compression configuration (if set to NULL, default encoder
* configuration parameters are used).
* @retrun The size of the buffer required.
*/
lzg_uint32_t LZG_WorkMemSize(lzg_encoder_config_t *config);
/**
* Encode uncompressed data using the LZG coder (i.e. compress the data).
* @param[in] in Input (uncompressed) buffer.
* @param[in] insize Size of the input buffer (number of bytes).
* @param[out] out Output (compressed) buffer.
* @param[in] outsize Size of the output buffer (number of bytes).
* @param[in] config Compression configuration (if set to NULL, default encoder
* configuration parameters are used).
* @return The size of the encoded data, or zero if the function failed
* (e.g. if the end of the output buffer was reached before the
* entire input buffer was encoded).
* @note For the slow method (config->fast = 0), the memory requirement during
* compression is 136 KB (LZG_LEVEL_1) to 2 MB (LZG_LEVEL_9). For the fast
* method (config->fast = 1), the memory requirement is 64 MB (LZG_LEVEL_1) to
* 66 MB (LZG_LEVEL_9). Also note that these figures are doubled on 64-bit
* systems.
*/
lzg_uint32_t LZG_Encode(const unsigned char *in, lzg_uint32_t insize,
unsigned char *out, lzg_uint32_t outsize,
lzg_encoder_config_t *config);
/**
* Encode uncompressed data using the LZG coder (i.e. compress the data).
* @param[in] in Input (uncompressed) buffer.
* @param[in] insize Size of the input buffer (number of bytes).
* @param[out] out Output (compressed) buffer.
* @param[in] outsize Size of the output buffer (number of bytes).
* @param[in] config Compression configuration (if set to NULL, default encoder
* configuration parameters are used).
* @param[in] workmem Buffer to be used for compression, or NULL. See
* @ref LZG_WorkMemSize.
* @return The size of the encoded data, or zero if the function failed
* (e.g. if the end of the output buffer was reached before the
* entire input buffer was encoded).
* @note For the slow method (config->fast = 0), the memory requirement during
* compression is 136 KB (LZG_LEVEL_1) to 2 MB (LZG_LEVEL_9). For the fast
* method (config->fast = 1), the memory requirement is 64 MB (LZG_LEVEL_1) to
* 66 MB (LZG_LEVEL_9). Also note that these figures are doubled on 64-bit
* systems.
*/
lzg_uint32_t LZG_EncodeFull(const unsigned char *in, lzg_uint32_t insize,
unsigned char *out, lzg_uint32_t outsize,
lzg_encoder_config_t *config,
void *workmem);
/**
* Determine the size of the decoded data for a given LZG coded buffer.
* @param[in] in Input (compressed) buffer.
* @param[in] insize Size of the input buffer (number of bytes). This does
* not have to be the size of the entire compressed data, but
* it has to be at least 7 bytes (the first few bytes of the
* header, including the decompression size).
* @return The size of the decoded data, or zero if the function failed
* (e.g. if the magic header ID could not be found).
*/
lzg_uint32_t LZG_DecodedSize(const unsigned char *in, lzg_uint32_t insize);
/**
* Decode LZG coded data.
* @param[in] in Input (compressed) buffer.
* @param[in] insize Size of the input buffer (number of bytes).
* @param[out] out Output (uncompressed) buffer.
* @param[in] outsize Size of the output buffer (number of bytes).
* @return The size of the decoded data, or zero if the function failed
* (e.g. if the end of the output buffer was reached before the
* entire input buffer was decoded).
*/
lzg_uint32_t LZG_Decode(const unsigned char *in, lzg_uint32_t insize,
unsigned char *out, lzg_uint32_t outsize);
/**
* Get the version of the LZG library.
* @return The version of the LZG library, on the same format as
* @ref LZG_VERNUM.
*/
lzg_uint32_t LZG_Version(void);
/**
* Get the version string of the LZG library.
* @return The version of the LZG library, on the same format as
* @ref LZG_VERSION.
*/
const char* LZG_VersionString(void);
#ifdef __cplusplus
}
#endif
#endif // _LIBLZG_H_

View File

@ -0,0 +1,25 @@
#pragma once
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
/* Defines all of the temporary library functions.
* All of this must be moved into the Chroma stdlib.
* They exist here as guidance, and as utility for the kernel itself.
* If need be, they can also be moved into a trimmed-down "kernel libc" or "libk".
*/
#include <lainlib/vector/vector.h>
#include <lainlib/list/list.h>
#include <lainlib/mutex/spinlock.h>
#include <lainlib/mutex/ticketlock.h>
#include <lainlib/compression/lzg.h>

View File

@ -0,0 +1,34 @@
#include <stdbool.h>
typedef struct list_entry {
struct list_entry* Previous;
struct list_entry* Next;
} list_entry_t;
#define UNSAFE_CAST(ptr, type, member) \
((type*)((char*)(ptr) - (char*)offsetof(type, member)))
#define LISTNEW(var) \
((list_entry_t){ 0, 0 })
void ListAdd(list_entry_t* Head, list_entry_t* New);
void ListEmplaceBack(list_entry_t* Head, list_entry_t* Tail);
void ListRemove(list_entry_t* List);
bool ListIsEmpty(list_entry_t* Head);
#define LISTNEXT(current, member) \
UNSAFE_CAST((current)->member.next, typeof(*(current)), member);
#define LISTPREV(current, member) \
UNSAFE_CAST((current)->member.prev, typeof(*(curent)), member)
#define LISTFOREACH(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define LISTFOREACHENTRY(pos, head, member) \
for(pos = UNSAFE_CAST((head)->next, typeof(*(pos)), member); &pos->member != (head); pos = LISTNEXT(pos, member))
#define LASTENTRY 0

View File

@ -0,0 +1,22 @@
#pragma once
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
typedef volatile int spinlock_t;
/* A set of macros that acquire and release a mutex spinlock. */
//TODO: this *needs* to be moved to a kernel header.
#define SPINLOCK(name) \
while( !__sync_bool_compare_and_swap(name, 0, 1)); \
__sync_synchronize();
#define SPUNLOCK(name) \
__sync_synchronize(); \
name = 0;

View File

@ -0,0 +1,32 @@
#pragma once
#include <stdbool.h>
#include <stdatomic.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
/* This file provides a simple implementation of a ticket-based locking system.
* You should probably prefer Spinlock over Ticketlock.
*
* Create a new lock with NEW_TICKETLOCK(),
* lock a resource with TicketLock().
*
* Use TicketUnlock() to free the resource after you are done.
*
*/
typedef struct {
atomic_size_t NowServing;
atomic_size_t NextTicket;
} ticketlock_t;
#define NEW_TICKETLOCK() (ticketlock_t{0})
void TicketLock(ticketlock_t* Lock);
bool TicketAttemptLock(ticketlock_t* Lock);
void TicketUnlock(ticketlock_t* Lock);

View File

@ -0,0 +1,30 @@
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
#pragma once
#include<stddef.h>
#include<stdint.h>
#include <lainlib/mutex/spinlock.h>
struct vector_t {
void** items;
size_t n;
spinlock_t vector_lock;
};
int VectorRemoveItem(struct vector_t* vec, void* item);
int VectorRemove(struct vector_t* vec, size_t index);
void* VectorGet(struct vector_t* vec, size_t index);
int VectorInsert(struct vector_t* vec, void* item, size_t index);
int VectorAppend(struct vector_t* vec, void* item);
int VectorDestroy(struct vector_t* vec);

View File

@ -0,0 +1,190 @@
/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; -*- */
/*
* This file is part of liblzg.
*
* Copyright (c) 2010 Marcus Geelnard
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would
* be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include <lainlib/lainlib.h>
/*-- PRIVATE -----------------------------------------------------------------*/
/* Internal definitions */
#define LZG_HEADER_SIZE 16
#define LZG_METHOD_COPY 0
#define LZG_METHOD_LZG1 1
/* Endian and alignment independent reader for 32-bit integers */
#define _LZG_GetUINT32(in, offs) \
((((lzg_uint32_t)in[offs]) << 24) | \
(((lzg_uint32_t)in[offs+1]) << 16) | \
(((lzg_uint32_t)in[offs+2]) << 8) | \
((lzg_uint32_t)in[offs+3]))
/* Calculate the checksum */
static lzg_uint32_t _LZG_CalcChecksum(const unsigned char *data, lzg_uint32_t size)
{
unsigned short a = 1, b = 0;
unsigned char *end = (unsigned char *)data + size;
while (data != end)
{
a += *data++;
b += a;
}
return (((lzg_uint32_t)b) << 16) | a;
}
/* LUT for decoding the copy length parameter */
static const unsigned char _LZG_LENGTH_DECODE_LUT[32] = {
2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
18,19,20,21,22,23,24,25,26,27,28,29,35,48,72,128
};
/*-- PUBLIC ------------------------------------------------------------------*/
lzg_uint32_t LZG_DecodedSize(const unsigned char *in, lzg_uint32_t insize)
{
/* Check header */
if ((insize < 7) || (in[0] != 'L') || (in[1] != 'Z') || (in[2] != 'G'))
return 0;
/* Get output buffer size */
return _LZG_GetUINT32(in, 3);
}
lzg_uint32_t LZG_Decode(const unsigned char *in, lzg_uint32_t insize,
unsigned char *out, lzg_uint32_t outsize)
{
unsigned char *src, *inEnd, *dst, *outEnd, *copy, symbol, b, b2;
unsigned char m1, m2, m3, m4, method;
lzg_uint32_t i, length, offset, encodedSize, decodedSize, checksum;
/* Check magic ID */
if ((insize < LZG_HEADER_SIZE) || (in[0] != 'L') || (in[1] != 'Z') || (in[2] != 'G'))
return 0;
/* Get header data */
decodedSize = _LZG_GetUINT32(in, 3);
encodedSize = _LZG_GetUINT32(in, 7);
checksum = _LZG_GetUINT32(in, 11);
/* Check sizes */
if ((outsize < decodedSize) || (encodedSize != (insize - LZG_HEADER_SIZE)))
return 0;
/* Check checksum */
if (_LZG_CalcChecksum(&in[LZG_HEADER_SIZE], encodedSize) != checksum)
return 0;
/* Initialize the byte streams */
src = (unsigned char *)in + LZG_HEADER_SIZE;;
inEnd = ((unsigned char *)in) + insize;
dst = out;
outEnd = out + outsize;
/* Check which method to use */
method = in[15];
if (method == LZG_METHOD_LZG1)
{
if (!((src + 4) <= inEnd)) return 0;
m1 = *src++; m2 = *src++; m3 = *src++; m4 = *src++;
/* Main decompression loop */
while (src < inEnd)
{
symbol = *src++;
if ((symbol != m1) && (symbol != m2) && (symbol != m3) && (symbol != m4))
{
/* Literal copy */
if (!(dst < outEnd)) return 0;
*dst++ = symbol;
}
else
{
/* Decode offset / length parameters */
if (!(src < inEnd)) return 0;
if ((b = *src++))
{
if (symbol == m1)
{
/* Distant copy */
if (!((src + 2) <= inEnd)) return 0;
length = _LZG_LENGTH_DECODE_LUT[b & 0x1f];
b2 = *src++;
offset = (((unsigned int)(b & 0xe0)) << 11) |
(((unsigned int)b2) << 8) |
(*src++);
offset += 2056;
}
else if (symbol == m2)
{
/* Medium copy */
if (!(src < inEnd)) return 0;
length = _LZG_LENGTH_DECODE_LUT[b & 0x1f];
b2 = *src++;
offset = (((unsigned int)(b & 0xe0)) << 3) | b2;
offset += 8;
}
else if (symbol == m3)
{
/* Short copy */
length = (b >> 6) + 3;
offset = (b & 0x3f) + 8;
}
else
{
/* Near copy (including RLE) */
length = _LZG_LENGTH_DECODE_LUT[b & 0x1f];
offset = (b >> 5) + 1;
}
/* Copy the corresponding data from the history window */
copy = dst - offset;
if (!((copy >= out) && ((dst + length) <= outEnd))) return 0;
for (i = 0; i < length; ++i)
*dst++ = *copy++;
}
else
{
/* Literal copy (single occurance of a marker symbol) */
if (!(dst < outEnd)) return 0;
*dst++ = symbol;
}
}
}
}
else if (method == LZG_METHOD_COPY)
{
/* Plain copy */
while ((src < inEnd) && (dst < outEnd))
*dst++ = *src++;
}
/* All OK? */
if ((unsigned int)(dst - out) != decodedSize)
return 0;
else
return decodedSize;
}

View File

@ -0,0 +1,27 @@
#include <lainlib/list/list.h>
void ListAdd(list_entry_t* Head, list_entry_t* New) {
New->Next = Head->Next;
New->Previous = Head;
New->Next->Previous = New;
Head->Next = New;
}
void ListEmplaceBack(list_entry_t* Head, list_entry_t* New) {
New->Next = Head;
New->Previous = Head->Previous;
New->Previous->Next = New;
Head->Previous = New;
}
void ListRemove(list_entry_t* Entry) {
Entry->Next->Previous = Entry->Previous;
Entry->Previous->Next = Entry->Next;
Entry->Previous = (void*)0xDEADull;
Entry->Next = (void*)0xBEEFull;
}
bool ListIsEmpty(list_entry_t* Head) {
return Head->Next == Head;
}

View File

@ -0,0 +1,21 @@
#include <kernel/chroma.h>
#include <lainlib/lainlib.h>
void TicketLock(ticketlock_t* Lock) {
size_t Ticket = atomic_fetch_add_explicit(&Lock->NextTicket, 1, memory_order_relaxed);
while(atomic_load_explicit(&Lock->NowServing, memory_order_acquire) != Ticket) {
PAUSE;
}
}
bool TicketAttemptLock(ticketlock_t* Lock) {
size_t Ticket = atomic_load_explicit(&Lock->NowServing, memory_order_relaxed);
return atomic_compare_exchange_strong_explicit(&Lock->NowServing, &Ticket, Ticket + 1, memory_order_acquire, memory_order_relaxed);
}
void TicketUnlock(ticketlock_t* Lock) {
size_t NextTicket = atomic_load_explicit(&Lock->NowServing, memory_order_relaxed) + 1;
atomic_store_explicit(&Lock->NowServing, NextTicket, memory_order_release);
}

68
chroma/lainlib/vector.c Normal file
View File

@ -0,0 +1,68 @@
#include <templib/templib.h>
/************************
*** Team Kitty, 2020 ***
*** Chroma ***
***********************/
/* This file provides a Chroma implementation of std::vector, a C++ standard library class.
* It has a lot of work left to be done, but it's usable for its intended function (Graphics)
*/
int VectorRemoveItem(struct vector_t* vec, void* item) {
//TODO
return -1;
}
int VectorRemove(struct vector_t* vec, size_t index) {
if (!vec) return 0;
//TODO: Vector spinlock
// AcqSpinlock(&vec->lock);
if((index + 1) > vec->n) return 0;
vec->items[index] = NULL;
for (int i = 0; i < vec->n; i++) {
vec->items[i] = vec->items[i + 1];
}
//TODO: vector reallocate
// realloc(vec->items, vec->n - 1);
vec->n--;
// ReleaseSpinlock(&vec->lock);
return 1;
}
void* VectorGet(struct vector_t* vec, size_t index) {
if(!vec) return 0;
//TODO: Vector spinlock
// AcqSpinlock(&vec->lock);
if((index + 1) > vec->n) return NULL;
// ReleaseSpinlock(&vec->lock);
return vec->items[index];
}
int VectorInsert(struct vector_t* vec, void* item, size_t index) {
}
int VectorAppend(struct vector_t* vec, void* item) {
}
int VectorDestroy(struct vector_t* vec) {
}