aboutsummaryrefslogtreecommitdiff
path: root/libs/libc
diff options
context:
space:
mode:
authorMarvin Borner2021-03-26 21:55:50 +0100
committerMarvin Borner2021-03-26 22:02:20 +0100
commit05498860e8f7b1e8bb27880bc7526de026694804 (patch)
tree3bddf16e9439a950a3810d45e42a5cefdbcb7663 /libs/libc
parenta96e9c4c858d47f61b89d879aa0ce6a02bdacb38 (diff)
Renamed libs
Cleaner and more flexible.
Diffstat (limited to 'libs/libc')
-rw-r--r--libs/libc/Makefile42
-rw-r--r--libs/libc/alloc.c425
-rw-r--r--libs/libc/conv.c145
-rw-r--r--libs/libc/cpu.c182
-rw-r--r--libs/libc/crt/crt0.asm15
-rw-r--r--libs/libc/crypto.c166
-rw-r--r--libs/libc/errno.c14
-rw-r--r--libs/libc/inc/arg.h11
-rw-r--r--libs/libc/inc/assert.h28
-rw-r--r--libs/libc/inc/conv.h15
-rw-r--r--libs/libc/inc/cpu.h110
-rw-r--r--libs/libc/inc/crypto.h11
-rw-r--r--libs/libc/inc/def.h59
-rw-r--r--libs/libc/inc/errno.h52
-rw-r--r--libs/libc/inc/input.h279
-rw-r--r--libs/libc/inc/ioctl.h11
-rw-r--r--libs/libc/inc/list.h29
-rw-r--r--libs/libc/inc/math.h8
-rw-r--r--libs/libc/inc/mem.h29
-rw-r--r--libs/libc/inc/print.h27
-rw-r--r--libs/libc/inc/random.h14
-rw-r--r--libs/libc/inc/socket.h38
-rw-r--r--libs/libc/inc/stack.h28
-rw-r--r--libs/libc/inc/str.h22
-rw-r--r--libs/libc/inc/sys.h130
-rw-r--r--libs/libc/inc/vec.h36
-rw-r--r--libs/libc/list.c138
-rw-r--r--libs/libc/math.c17
-rw-r--r--libs/libc/mem.c121
-rw-r--r--libs/libc/print.c257
-rw-r--r--libs/libc/random.c71
-rw-r--r--libs/libc/sanitize.c228
-rw-r--r--libs/libc/stack.c126
-rw-r--r--libs/libc/str.c207
-rw-r--r--libs/libc/sys.c203
35 files changed, 3294 insertions, 0 deletions
diff --git a/libs/libc/Makefile b/libs/libc/Makefile
new file mode 100644
index 0000000..1c66f43
--- /dev/null
+++ b/libs/libc/Makefile
@@ -0,0 +1,42 @@
+# MIT License, Copyright (c) 2020 Marvin Borner
+
+# TODO: Remove cpu from libc?
+COBJS = sanitize.o \
+ errno.o \
+ str.o \
+ alloc.o \
+ mem.o \
+ math.o \
+ crypto.o \
+ conv.o \
+ print.o \
+ cpu.o \
+ sys.o \
+ list.o \
+ stack.o \
+ random.o
+CC = ccache ../../cross/opt/bin/i686-elf-gcc
+LD = ccache ../../cross/opt/bin/i686-elf-ld
+AR = ccache ../../cross/opt/bin/i686-elf-ar
+AS = ccache nasm
+
+CFLAGS = $(CFLAGS_DEFAULT) -Iinc/
+
+ASFLAGS = -f elf32
+
+%.o: %.c
+ @$(CC) -c $(CFLAGS) $< -o $@
+
+libc: CFLAGS += -Duserspace
+libc: $(COBJS)
+ @$(AS) $(ASFLAGS) crt/crt0.asm -o crt0.o
+ @mkdir -p ../../build/
+ @$(AR) rcs ../../build/libc.a crt0.o $+
+
+libk: CFLAGS += -Dkernel -ffreestanding -I../../kernel/inc/ $(CFLAGS_EXTRA)
+libk: $(COBJS)
+ @mkdir -p ../../build/
+ @$(AR) rcs ../../build/libk.a $+
+
+clean:
+ @find . -name "*.o" -type f -delete
diff --git a/libs/libc/alloc.c b/libs/libc/alloc.c
new file mode 100644
index 0000000..b8139d0
--- /dev/null
+++ b/libs/libc/alloc.c
@@ -0,0 +1,425 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+// Mostly by Durand Miller, released into public domain
+
+#include <assert.h>
+#include <cpu.h>
+#include <mem.h>
+
+#ifdef kernel
+
+#include <mm.h>
+
+static void *liballoc_alloc(u32 p)
+{
+ return memory_alloc(virtual_kernel_dir(), p, MEMORY_CLEAR);
+}
+
+static int liballoc_free(void *ptr, u32 p)
+{
+ memory_free(virtual_kernel_dir(), memory_range((u32)ptr, (u32)p));
+ return 0;
+}
+
+#else
+
+#include <sys.h>
+
+static void *liballoc_alloc(u32 p)
+{
+ u32 addr;
+ assert(sys_alloc(p, &addr) == EOK);
+ return (void *)addr;
+}
+
+static int liballoc_free(void *ptr, u32 p)
+{
+ UNUSED(p);
+ assert(sys_free(ptr) == EOK);
+ return 0;
+}
+
+#endif
+
+static int locked = 0;
+
+static int liballoc_lock(void)
+{
+ spinlock(&locked);
+ return 0;
+}
+
+static int liballoc_unlock(void)
+{
+ locked = 0;
+ return 0;
+}
+
+#define ALIGNMENT 16
+#define ALIGN_UP(__addr, __align) (((__addr) + (__align)-1) & ~((__align)-1))
+#define ALIGN_DOWN(__addr, __align) ((__addr) & ~((__align)-1))
+
+#define USE_CASE1
+#define USE_CASE2
+#define USE_CASE3
+#define USE_CASE4
+#define USE_CASE5
+#define LIBALLOC_MAGIC 0x900df00d
+#define LIBALLOC_DEAD 0xbaadf00d
+
+struct liballoc_major {
+ struct liballoc_major *prev;
+ struct liballoc_major *next;
+ u32 pages;
+ u32 size;
+ u32 usage;
+ struct liballoc_minor *first;
+};
+
+struct liballoc_minor {
+ struct liballoc_minor *prev;
+ struct liballoc_minor *next;
+ struct liballoc_major *block;
+ u32 magic;
+ u32 size;
+ u32 req_size;
+};
+
+#define MAJOR_SIZE (ALIGN_UP(sizeof(struct liballoc_major), 16))
+#define MINOR_SIZE (ALIGN_UP(sizeof(struct liballoc_minor), 16))
+
+static struct liballoc_major *l_mem_root = NULL;
+static struct liballoc_major *l_best_bet = NULL;
+
+static u32 l_page_size = 4096;
+static u32 l_page_count = 16;
+
+static struct liballoc_major *allocate_new_page(u32 size)
+{
+ u32 st = size + MAJOR_SIZE + MINOR_SIZE;
+
+ if ((st % l_page_size) == 0)
+ st = st / (l_page_size);
+ else
+ st = st / (l_page_size) + 1;
+
+ st = MAX(st, l_page_count);
+
+ struct liballoc_major *maj = (struct liballoc_major *)liballoc_alloc(st * l_page_size);
+
+ if (maj == NULL)
+ return NULL;
+
+ maj->prev = NULL;
+ maj->next = NULL;
+ maj->pages = st;
+ maj->size = st * l_page_size;
+ maj->usage = MAJOR_SIZE;
+ maj->first = NULL;
+
+ return maj;
+}
+
+static void *_malloc(u32 req_size)
+{
+ req_size = ALIGN_UP(req_size, 16);
+
+ u32 best_size = 0;
+ u32 size = req_size;
+
+ liballoc_lock();
+
+ if (size == 0) {
+ liballoc_unlock();
+ return malloc(1);
+ }
+
+ if (l_mem_root == NULL) {
+ l_mem_root = allocate_new_page(size);
+ if (l_mem_root == NULL) {
+ liballoc_unlock();
+ panic("Malloc failed!\n");
+ }
+ }
+
+ struct liballoc_major *maj = l_mem_root;
+ u8 started_bet = 0;
+
+ if (l_best_bet != NULL) {
+ best_size = l_best_bet->size - l_best_bet->usage;
+
+ if (best_size > (size + MINOR_SIZE)) {
+ maj = l_best_bet;
+ started_bet = 1;
+ }
+ }
+
+ while (maj != NULL) {
+ u32 diff = maj->size - maj->usage;
+ if (best_size < diff) {
+ l_best_bet = maj;
+ best_size = diff;
+ }
+
+#ifdef USE_CASE1
+ if (diff < (size + MINOR_SIZE)) {
+ if (maj->next != NULL) {
+ maj = maj->next;
+ continue;
+ }
+
+ if (started_bet == 1) {
+ maj = l_mem_root;
+ started_bet = 0;
+ continue;
+ }
+
+ maj->next = allocate_new_page(size);
+ if (maj->next == NULL)
+ break;
+ maj->next->prev = maj;
+ maj = maj->next;
+ }
+#endif
+
+#ifdef USE_CASE2
+ if (maj->first == NULL) {
+ maj->first = (struct liballoc_minor *)((u32)maj + MAJOR_SIZE);
+
+ 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 + MINOR_SIZE;
+ void *p = (void *)((u32)(maj->first) + MINOR_SIZE);
+ liballoc_unlock();
+ return p;
+ }
+#endif
+
+#ifdef USE_CASE3
+ diff = (u32)(maj->first);
+ diff -= (u32)maj;
+ diff -= MAJOR_SIZE;
+
+ if (diff >= (size + MINOR_SIZE)) {
+ maj->first->prev = (struct liballoc_minor *)((u32)maj + MAJOR_SIZE);
+ 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 + MINOR_SIZE;
+ void *p = (void *)((u32)(maj->first) + MINOR_SIZE);
+ liballoc_unlock();
+ return p;
+ }
+#endif
+
+#ifdef USE_CASE4
+ struct liballoc_minor *min = maj->first;
+
+ while (min != NULL) {
+ if (min->next == NULL) {
+ diff = (u32)(maj) + maj->size;
+ diff -= (u32)min;
+ diff -= MINOR_SIZE;
+ diff -= min->size;
+ if (diff >= (size + MINOR_SIZE)) {
+ min->next =
+ (struct liballoc_minor *)((u32)min + MINOR_SIZE +
+ 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 + MINOR_SIZE;
+ void *p = (void *)((u32)min + MINOR_SIZE);
+ liballoc_unlock();
+ return p;
+ }
+ }
+
+ if (min->next != NULL) {
+ diff = (u32)(min->next);
+ diff -= (u32)min;
+ diff -= MINOR_SIZE;
+ diff -= min->size;
+
+ if (diff >= (size + MINOR_SIZE)) {
+ struct liballoc_minor *new_min =
+ (struct liballoc_minor *)((u32)min + MINOR_SIZE +
+ 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 + MINOR_SIZE;
+ void *p = (void *)((u32)new_min + MINOR_SIZE);
+ liballoc_unlock();
+ return p;
+ }
+ }
+
+ min = min->next;
+ }
+#endif
+
+#ifdef USE_CASE5
+ if (maj->next == NULL) {
+ if (started_bet == 1) {
+ maj = l_mem_root;
+ started_bet = 0;
+ continue;
+ }
+ maj->next = allocate_new_page(size);
+ if (maj->next == NULL)
+ break;
+ maj->next->prev = maj;
+ }
+#endif
+ maj = maj->next;
+ }
+
+ liballoc_unlock();
+
+ panic("Malloc failed!\n");
+ return NULL;
+}
+
+static void _free(void *ptr)
+{
+ if (ptr == NULL) {
+ return;
+ }
+
+ liballoc_lock();
+
+ struct liballoc_minor *min = (struct liballoc_minor *)((u32)ptr - MINOR_SIZE);
+
+ if (min->magic != LIBALLOC_MAGIC) {
+ liballoc_unlock();
+ return;
+ }
+
+ struct liballoc_major *maj = min->block;
+ maj->usage -= (min->size + MINOR_SIZE);
+ min->magic = LIBALLOC_DEAD;
+
+ 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;
+ if (maj->first == NULL) {
+ if (l_mem_root == maj)
+ l_mem_root = maj->next;
+ if (l_best_bet == maj)
+ l_best_bet = NULL;
+ if (maj->prev != NULL)
+ maj->prev->next = maj->next;
+ if (maj->next != NULL)
+ maj->next->prev = maj->prev;
+ liballoc_free(maj, maj->pages * l_page_size);
+ } else {
+ if (l_best_bet != NULL) {
+ int best_size = l_best_bet->size - l_best_bet->usage;
+ int maj_size = maj->size - maj->usage;
+ if (maj_size > best_size)
+ l_best_bet = maj;
+ }
+ }
+ liballoc_unlock();
+}
+
+static void *_realloc(void *ptr, u32 size)
+{
+ size = ALIGN_UP(size, 16);
+
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ }
+
+ if (ptr == NULL)
+ return malloc(size);
+
+ liballoc_lock();
+ struct liballoc_minor *min = (struct liballoc_minor *)((u32)ptr - MINOR_SIZE);
+
+ if (min->magic != LIBALLOC_MAGIC) {
+ liballoc_unlock();
+ panic("Malloc failed!\n");
+ return NULL;
+ }
+
+ if (min->size >= size) {
+ min->req_size = size;
+ liballoc_unlock();
+ return ptr;
+ }
+
+ liballoc_unlock();
+
+ void *new_ptr = malloc(size);
+ memcpy(new_ptr, ptr, min->req_size);
+ free(ptr);
+
+ return new_ptr;
+}
+
+#ifdef kernel
+#define PREFIX "K"
+#define FUNC printf
+#else
+#define PREFIX "U"
+#define FUNC log
+#endif
+
+void *zalloc(u32 size)
+{
+ void *ret = malloc(size);
+ memset(ret, 0, size);
+ return ret;
+}
+
+void *realloc(void *ptr, u32 size)
+{
+ return _realloc(ptr, size);
+}
+
+void *malloc_debug(u32 size, const char *file, int line, const char *func, const char *inp)
+{
+ assert(size < (100 << 20)); // Don't brag with memory pls
+ void *ret = _malloc(size);
+
+ (void)file;
+ (void)line;
+ (void)func;
+ (void)inp;
+ /* FUNC(PREFIX "MALLOC\t%s:%d: %s: 0x%x %dB (%s)\n", file, line, func, ret, size, inp); */
+ return ret;
+}
+
+void free_debug(void *ptr, const char *file, int line, const char *func, const char *inp)
+{
+ if (ptr)
+ _free(ptr);
+
+ (void)file;
+ (void)line;
+ (void)func;
+ (void)inp;
+ /* FUNC(PREFIX "FREE\t%s:%d: %s: 0x%x (%s)\n", file, line, func, ptr, inp); */
+}
diff --git a/libs/libc/conv.c b/libs/libc/conv.c
new file mode 100644
index 0000000..670fdb3
--- /dev/null
+++ b/libs/libc/conv.c
@@ -0,0 +1,145 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <conv.h>
+#include <def.h>
+#include <math.h>
+#include <mem.h>
+#include <str.h>
+
+static const char HTOA_TABLE[] = "0123456789ABCDEF";
+static const char ITOA_TABLE[] = "0123456789";
+
+int atoi(const char *str)
+{
+ u32 s_str = strlen(str);
+ if (!s_str)
+ return 0;
+
+ u8 negative = 0;
+ if (str[0] == '-')
+ negative = 1;
+
+ u32 i = 0;
+ if (negative)
+ i++;
+
+ int ret = 0;
+ for (; i < s_str; i++) {
+ ret += (str[i] - '0') * pow(10, (int)((s_str - i) - 1));
+ }
+
+ if (negative)
+ ret *= -1;
+ return ret;
+}
+
+char *htoa(u32 n)
+{
+ char *ret = (char *)malloc(10);
+
+ int i = 0;
+ while (n) {
+ ret[i++] = HTOA_TABLE[n & 0xF];
+ n >>= 4;
+ }
+
+ if (!i) {
+ ret[0] = '0';
+ i++;
+ }
+
+ for (; i <= 9; i++)
+ ret[i] = 0;
+
+ char *aux = strdup(ret);
+ free(ret);
+ ret = aux;
+
+ strinv(ret);
+ return ret;
+}
+
+int htoi(const char *str)
+{
+ u32 s_str = strlen(str);
+
+ u32 i = 0;
+ int ret = 0;
+ for (; i < s_str; i++) {
+ char c = str[i];
+ int aux = 0;
+ if (c >= '0' && c <= '9')
+ aux = c - '0';
+ else if (c >= 'A' && c <= 'F')
+ aux = (c - 'A') + 10;
+
+ ret += aux * pow(16, (int)((s_str - i) - 1));
+ }
+
+ return ret;
+}
+
+char *itoa(int n)
+{
+ if (!n) {
+ char *ret = (char *)malloc(2);
+ ret[0] = '0';
+ ret[1] = 0;
+ return ret;
+ }
+ u8 negative = (u8)(n < 0);
+ if (negative)
+ n *= -1;
+
+ int sz;
+ for (sz = 0; n % pow(10, sz) != n; sz++) {
+ }
+
+ char *ret = (char *)malloc((u32)(sz + 1));
+
+ for (int i = 0; i < sz; i++) {
+ int digit = (n % pow(10, i + 1)) / pow(10, i);
+ ret[i] = ITOA_TABLE[digit];
+ }
+ ret[sz] = 0;
+
+ if (negative) {
+ char *aux = (char *)malloc((u32)(sz + 2));
+ strcpy(aux, ret);
+ aux[sz] = '-';
+ aux[sz + 1] = 0;
+ free(ret);
+ ret = aux;
+ }
+
+ strinv(ret);
+ return ret;
+}
+
+char *conv_base(int value, char *result, int base, int is_signed)
+{
+ if (base < 2 || base > 36) {
+ *result = '\0';
+ return result;
+ }
+
+ char *ptr = result, *ptr1 = result, tmp_char;
+ int tmp_value;
+
+ do {
+ tmp_value = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"
+ [35 + (tmp_value - value * base)];
+ } while (value);
+
+ if (is_signed && tmp_value < 0)
+ *ptr++ = '-';
+ *ptr-- = '\0';
+ while (ptr1 < ptr) {
+ tmp_char = *ptr;
+ *ptr-- = *ptr1;
+ *ptr1++ = tmp_char;
+ }
+ return result;
+}
diff --git a/libs/libc/cpu.c b/libs/libc/cpu.c
new file mode 100644
index 0000000..8ca4d27
--- /dev/null
+++ b/libs/libc/cpu.c
@@ -0,0 +1,182 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// This file is a wrapper around some CPU asm calls
+
+#include <cpu.h>
+#include <def.h>
+#include <print.h>
+
+u8 inb(u16 port)
+{
+ u8 value;
+ __asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+
+u16 inw(u16 port)
+{
+ u16 value;
+ __asm__ volatile("inw %1, %0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+
+u32 inl(u16 port)
+{
+ u32 value;
+ __asm__ volatile("inl %1, %0" : "=a"(value) : "Nd"(port));
+ return value;
+}
+
+void insl(u16 port, void *addr, int n)
+{
+ __asm__ volatile("rep insl" ::"c"(n), // Count
+ "d"(port), // Port #
+ "D"(addr)); // Buffer
+}
+
+void outb(u16 port, u8 data)
+{
+ __asm__ volatile("outb %0, %1" ::"a"(data), "Nd"(port));
+}
+
+void outw(u16 port, u16 data)
+{
+ __asm__ volatile("outw %0, %1" ::"a"(data), "Nd"(port));
+}
+
+void outl(u16 port, u32 data)
+{
+ __asm__ volatile("outl %0, %1" ::"a"(data), "Nd"(port));
+}
+
+#ifdef kernel
+
+static void cpuid(int code, u32 *a, u32 *b, u32 *c, u32 *d)
+{
+ __asm__ volatile("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) : "a"(code));
+}
+
+static char *cpu_string(char buf[16])
+{
+ // wtf
+ cpuid(CPUID_VENDOR_STRING, (u32 *)(buf + 12), (u32 *)(buf), (u32 *)(buf + 8),
+ (u32 *)(buf + 4));
+
+ return buf;
+}
+
+void cpu_print(void)
+{
+ char buf[16] = { 0 };
+ printf("CPU vendor: %s\n", cpu_string(buf));
+}
+
+u32 cr0_get(void)
+{
+ u32 cr0;
+ __asm__ volatile("movl %%cr0, %%eax" : "=a"(cr0));
+ return cr0;
+}
+
+void cr0_set(u32 cr0)
+{
+ __asm__ volatile("movl %%eax, %%cr0" ::"a"(cr0));
+}
+
+u32 cr3_get(void)
+{
+ u32 cr3;
+ __asm__ volatile("movl %%cr0, %%eax" : "=a"(cr3));
+ return cr3;
+}
+
+void cr3_set(u32 cr3)
+{
+ __asm__ volatile("movl %%eax, %%cr3" ::"a"(cr3));
+}
+
+u32 cr4_get(void)
+{
+ u32 cr4;
+ __asm__ volatile("movl %%cr4, %%eax" : "=a"(cr4));
+ return cr4;
+}
+
+void cr4_set(u32 cr4)
+{
+ __asm__ volatile("movl %%eax, %%cr4" ::"a"(cr4));
+}
+
+static u32 cpu_cfeatures = 0;
+u8 cpu_has_cfeature(enum cpuid_features feature)
+{
+ return (cpu_cfeatures & feature) != 0;
+}
+
+static u32 cpu_dfeatures = 0;
+u8 cpu_has_dfeature(enum cpuid_features feature)
+{
+ return (cpu_dfeatures & feature) != 0;
+}
+
+static void fpu_handler(struct regs *r)
+{
+ UNUSED(r);
+ __asm__ volatile("clts");
+}
+
+static u8 fpu_state[512] __attribute__((aligned(16)));
+void fpu_restore(void)
+{
+ __asm__ volatile("fxrstor (%0)" ::"r"(fpu_state));
+}
+
+void cpu_enable_features(void)
+{
+ u32 a, b, c, d;
+ cpuid(CPUID_FEATURES, &a, &b, &c, &d);
+ cpu_cfeatures = c;
+ cpu_dfeatures = d;
+ if (cpu_has_dfeature(CPUID_FEAT_EDX_SSE)) {
+ cr0_set(cr0_get() & ~(1 << 2));
+ cr0_set(cr0_get() | (1 << 1));
+ cr4_set(cr4_get() | (3 << 9));
+ } else {
+ panic("No SSE support!\n");
+ }
+
+ if (cpu_has_dfeature(CPUID_FEAT_EDX_FPU)) {
+ __asm__ volatile("fninit");
+ __asm__ volatile("fxsave %0" : "=m"(fpu_state));
+ irq_install_handler(7, fpu_handler);
+ } else {
+ panic("No FPU support!\n");
+ }
+}
+
+void cli(void)
+{
+ __asm__ volatile("cli");
+}
+
+void sti(void)
+{
+ __asm__ volatile("sti");
+}
+
+void hlt(void)
+{
+ __asm__ volatile("hlt");
+}
+
+void idle(void)
+{
+ while (1)
+ hlt();
+}
+
+void loop(void)
+{
+ cli();
+ idle();
+}
+#endif
diff --git a/libs/libc/crt/crt0.asm b/libs/libc/crt/crt0.asm
new file mode 100644
index 0000000..e002952
--- /dev/null
+++ b/libs/libc/crt/crt0.asm
@@ -0,0 +1,15 @@
+; MIT License, Copyright (c) 2020 Marvin Borner
+
+section .text
+
+extern main
+extern exit
+extern atexit_trigger
+
+global _start
+_start:
+ call main
+
+ push eax
+ call exit
+ jmp $
diff --git a/libs/libc/crypto.c b/libs/libc/crypto.c
new file mode 100644
index 0000000..310931d
--- /dev/null
+++ b/libs/libc/crypto.c
@@ -0,0 +1,166 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#include <crypto.h>
+#include <def.h>
+#include <mem.h>
+
+/**
+ * MD5
+ */
+
+#define MD5_LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+
+static const u32 md5_tab[64] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613,
+ 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
+ 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d,
+ 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,
+ 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+ 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
+ 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb,
+ 0xeb86d391,
+};
+
+static const u32 md5_rounds[] = {
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9,
+ 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
+};
+
+static void md5_u32_to_bytes(u32 val, u8 *bytes)
+{
+ bytes[0] = (u8)val;
+ bytes[1] = (u8)(val >> 8);
+ bytes[2] = (u8)(val >> 16);
+ bytes[3] = (u8)(val >> 24);
+}
+
+static u32 md5_bytes_to_u32(u8 *bytes)
+{
+ return (u32)bytes[0] | ((u32)bytes[1] << 8) | ((u32)bytes[2] << 16) | ((u32)bytes[3] << 24);
+}
+
+void md5(const void *initial_msg, u32 initial_len, u8 digest[16])
+{
+ u32 w[16] = { 0 };
+
+ u32 h0 = 0x67452301;
+ u32 h1 = 0xefcdab89;
+ u32 h2 = 0x98badcfe;
+ u32 h3 = 0x10325476;
+
+ u32 new_len;
+ for (new_len = initial_len + 1; new_len % (512 / 8) != 448 / 8; new_len++)
+ ;
+
+ u8 *msg = malloc(new_len + 8);
+ memcpy(msg, initial_msg, initial_len);
+ msg[initial_len] = 0x80;
+ for (u32 offset = initial_len + 1; offset < new_len; offset++)
+ msg[offset] = 0;
+
+ md5_u32_to_bytes(initial_len * 8, msg + new_len);
+ md5_u32_to_bytes(initial_len >> 29, msg + new_len + 4);
+
+ for (u32 offset = 0; offset < new_len; offset += (512 / 8)) {
+ for (u32 i = 0; i < 16; i++)
+ w[i] = md5_bytes_to_u32(msg + offset + i * 4);
+
+ u32 a = h0;
+ u32 b = h1;
+ u32 c = h2;
+ u32 d = h3;
+
+ u32 f, g;
+ for (u32 i = 0; i < 64; i++) {
+ if (i < 16) {
+ f = (b & c) | ((~b) & d);
+ g = i;
+ } else if (i < 32) {
+ f = (d & b) | ((~d) & c);
+ g = (5 * i + 1) % 16;
+ } else if (i < 48) {
+ f = b ^ c ^ d;
+ g = (3 * i + 5) % 16;
+ } else {
+ f = c ^ (b | (~d));
+ g = (7 * i) % 16;
+ }
+
+ u32 temp = d;
+ d = c;
+ c = b;
+ b = b + MD5_LEFTROTATE((a + f + md5_tab[i] + w[g]), md5_rounds[i]);
+ a = temp;
+ }
+
+ h0 += a;
+ h1 += b;
+ h2 += c;
+ h3 += d;
+ }
+
+ free(msg);
+
+ md5_u32_to_bytes(h0, digest);
+ md5_u32_to_bytes(h1, digest + 4);
+ md5_u32_to_bytes(h2, digest + 8);
+ md5_u32_to_bytes(h3, digest + 12);
+}
+
+/**
+ * CRC32
+ */
+
+static const u32 crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
+ 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
+ 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
+ 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
+ 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
+ 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
+ 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
+ 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
+ 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
+ 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
+ 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
+ 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
+ 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
+ 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
+ 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
+ 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
+ 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
+ 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
+ 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
+ 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+u32 crc32(u32 crc, const void *buf, u32 size)
+{
+ const u8 *p = buf;
+ crc = crc ^ ~0UL;
+
+ while (size--)
+ crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+ return crc ^ ~0UL;
+}
diff --git a/libs/libc/errno.c b/libs/libc/errno.c
new file mode 100644
index 0000000..7204f5b
--- /dev/null
+++ b/libs/libc/errno.c
@@ -0,0 +1,14 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#include <def.h>
+#include <errno.h>
+#ifdef userspace
+
+static u32 error = 0;
+
+u32 *__errno(void)
+{
+ return &error;
+}
+
+#endif
diff --git a/libs/libc/inc/arg.h b/libs/libc/inc/arg.h
new file mode 100644
index 0000000..73e592d
--- /dev/null
+++ b/libs/libc/inc/arg.h
@@ -0,0 +1,11 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef ARG_H
+#define ARG_H
+
+typedef __builtin_va_list va_list;
+#define va_start __builtin_va_start
+#define va_end __builtin_va_end
+#define va_arg __builtin_va_arg
+
+#endif
diff --git a/libs/libc/inc/assert.h b/libs/libc/inc/assert.h
new file mode 100644
index 0000000..3656c33
--- /dev/null
+++ b/libs/libc/inc/assert.h
@@ -0,0 +1,28 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef ASSERT_H
+#define ASSERT_H
+
+#include <print.h>
+
+#ifdef kernel
+#include <proc.h>
+#define assert(exp) \
+ if (!(exp)) { \
+ printf("%s:%d: %s: Kernel assertion '%s' failed\n", __FILE__, __LINE__, __func__, \
+ #exp); \
+ struct proc *assert_proc = proc_current(); \
+ if (assert_proc) \
+ proc_exit(assert_proc, 1); \
+ else \
+ __asm__ volatile("cli\nhlt"); \
+ }
+#elif defined(userspace)
+#define assert(exp) \
+ if (!(exp)) \
+ err(1, "%s:%d: %s: Assertion '%s' failed\n", __FILE__, __LINE__, __func__, #exp);
+#else
+#error "No lib target specified. Please use -Dkernel or -Duserspace"
+#endif
+
+#endif
diff --git a/libs/libc/inc/conv.h b/libs/libc/inc/conv.h
new file mode 100644
index 0000000..adf9003
--- /dev/null
+++ b/libs/libc/inc/conv.h
@@ -0,0 +1,15 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef CONV_H
+#define CONV_H
+
+#include <def.h>
+
+int atoi(const char *str);
+char *htoa(u32 n);
+int htoi(const char *str);
+char *itoa(int n);
+
+char *conv_base(int value, char *result, int base, int is_signed);
+
+#endif
diff --git a/libs/libc/inc/cpu.h b/libs/libc/inc/cpu.h
new file mode 100644
index 0000000..d709d86
--- /dev/null
+++ b/libs/libc/inc/cpu.h
@@ -0,0 +1,110 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef CPU_H
+#define CPU_H
+
+#include <def.h>
+
+u8 inb(u16 port);
+u16 inw(u16 port);
+u32 inl(u16 port);
+void insl(u16 port, void *addr, int n);
+
+void outb(u16 port, u8 data);
+void outw(u16 port, u16 data);
+void outl(u16 port, u32 data);
+
+static inline void spinlock(int *ptr)
+{
+ int prev;
+ do
+ __asm__ volatile("lock xchgl %0,%1" : "=a"(prev) : "m"(*ptr), "a"(1));
+ while (prev);
+}
+
+#ifdef kernel
+void cpu_print(void);
+void cpu_enable_features(void);
+void fpu_restore(void);
+
+u32 cr0_get(void);
+void cr0_set(u32 cr0);
+u32 cr3_get(void);
+void cr3_set(u32 cr3);
+u32 cr4_get(void);
+void cr4_set(u32 cr4);
+
+void cli(void);
+void sti(void);
+void hlt(void);
+void idle(void);
+void loop(void);
+
+enum cpuid_requests { CPUID_VENDOR_STRING, CPUID_FEATURES, CPUID_TLB, CPUID_SERIAL };
+enum cpuid_features {
+ CPUID_FEAT_ECX_SSE3 = 1u << 0,
+ CPUID_FEAT_ECX_PCLMUL = 1u << 1,
+ CPUID_FEAT_ECX_DTES64 = 1u << 2,
+ CPUID_FEAT_ECX_MONITOR = 1u << 3,
+ CPUID_FEAT_ECX_DS_CPL = 1u << 4,
+ CPUID_FEAT_ECX_VMX = 1u << 5,
+ CPUID_FEAT_ECX_SMX = 1u << 6,
+ CPUID_FEAT_ECX_EST = 1u << 7,
+ CPUID_FEAT_ECX_TM2 = 1u << 8,
+ CPUID_FEAT_ECX_SSSE3 = 1u << 9,
+ CPUID_FEAT_ECX_CID = 1u << 10,
+ CPUID_FEAT_ECX_FMA = 1u << 12,
+ CPUID_FEAT_ECX_CX16 = 1u << 13,
+ CPUID_FEAT_ECX_ETPRD = 1u << 14,
+ CPUID_FEAT_ECX_PDCM = 1u << 15,
+ CPUID_FEAT_ECX_PCIDE = 1u << 17,
+ CPUID_FEAT_ECX_DCA = 1u << 18,
+ CPUID_FEAT_ECX_SSE4_1 = 1u << 19,
+ CPUID_FEAT_ECX_SSE4_2 = 1u << 20,
+ CPUID_FEAT_ECX_x2APIC = 1u << 21,
+ CPUID_FEAT_ECX_MOVBE = 1u << 22,
+ CPUID_FEAT_ECX_POPCNT = 1u << 23,
+ CPUID_FEAT_ECX_AES = 1u << 25,
+ CPUID_FEAT_ECX_XSAVE = 1u << 26,
+ CPUID_FEAT_ECX_OSXSAVE = 1u << 27,
+ CPUID_FEAT_ECX_AVX = 1u << 28,
+ CPUID_FEAT_ECX_F16C = 1u << 29,
+ CPUID_FEAT_ECX_RDRND = 1u << 30,
+
+ CPUID_FEAT_EDX_FPU = 1u << 0,
+ CPUID_FEAT_EDX_VME = 1u << 1,
+ CPUID_FEAT_EDX_DE = 1u << 2,
+ CPUID_FEAT_EDX_PSE = 1u << 3,
+ CPUID_FEAT_EDX_TSC = 1u << 4,
+ CPUID_FEAT_EDX_MSR = 1u << 5,
+ CPUID_FEAT_EDX_PAE = 1u << 6,
+ CPUID_FEAT_EDX_MCE = 1u << 7,
+ CPUID_FEAT_EDX_CX8 = 1u << 8,
+ CPUID_FEAT_EDX_APIC = 1u << 9,
+ CPUID_FEAT_EDX_SEP = 1u << 11,
+ CPUID_FEAT_EDX_MTRR = 1u << 12,
+ CPUID_FEAT_EDX_PGE = 1u << 13,
+ CPUID_FEAT_EDX_MCA = 1u << 14,
+ CPUID_FEAT_EDX_CMOV = 1u << 15,
+ CPUID_FEAT_EDX_PAT = 1u << 16,
+ CPUID_FEAT_EDX_PSE36 = 1u << 17,
+ CPUID_FEAT_EDX_PSN = 1u << 18,
+ CPUID_FEAT_EDX_CLF = 1u << 19,
+ CPUID_FEAT_EDX_DTES = 1u << 21,
+ CPUID_FEAT_EDX_ACPI = 1u << 22,
+ CPUID_FEAT_EDX_MMX = 1u << 23,
+ CPUID_FEAT_EDX_FXSR = 1u << 24,
+ CPUID_FEAT_EDX_SSE = 1u << 25,
+ CPUID_FEAT_EDX_SSE2 = 1u << 26,
+ CPUID_FEAT_EDX_SS = 1u << 27,
+ CPUID_FEAT_EDX_HTT = 1u << 28,
+ CPUID_FEAT_EDX_TM1 = 1u << 29,
+ CPUID_FEAT_EDX_IA64 = 1u << 30,
+};
+
+u8 cpu_has_cfeature(enum cpuid_features feature);
+u8 cpu_has_dfeature(enum cpuid_features feature);
+
+#endif
+
+#endif
diff --git a/libs/libc/inc/crypto.h b/libs/libc/inc/crypto.h
new file mode 100644
index 0000000..bbe8d7e
--- /dev/null
+++ b/libs/libc/inc/crypto.h
@@ -0,0 +1,11 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#include <def.h>
+
+void md5(const void *initial_msg, u32 initial_len, u8 digest[16]);
+u32 crc32(u32 crc, const void *buf, u32 size);
+
+#endif
diff --git a/libs/libc/inc/def.h b/libs/libc/inc/def.h
new file mode 100644
index 0000000..708ffee
--- /dev/null
+++ b/libs/libc/inc/def.h
@@ -0,0 +1,59 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef DEF_H
+#define DEF_H
+
+/**
+ * Types
+ */
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed long s32;
+typedef unsigned long u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+/**
+ * Macros
+ */
+
+#define UNUSED(a) ((void)(a))
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define ABS(a) (((a) < 0) ? (-a) : (a))
+
+#define NORETURN __attribute__((noreturn))
+#define NO_SANITIZE __attribute__((no_sanitize("undefined")))
+#define PACKED __attribute__((packed))
+#define ALIGNED(align) __attribute__((aligned(align)))
+
+#define EOF (-1)
+#define NULL ((void *)0)
+
+#define U8_MAX 255
+#define S8_MAX 127
+#define S8_MIN -128
+#define U16_MAX 65535
+#define S16_MAX 32767
+#define S16_MIN -32768
+#define U32_MAX 4294967295
+#define S32_MAX 2147483647
+#define S32_MIN -2147483648
+
+#define LONG_MAX S32_MAX
+#define LONG_MIN S32_MIN
+
+#define MILLION 1000000
+#define BILLION 1000000000
+#define TRILLION 1000000000000
+#define QUADRILLION 1000000000000000
+
+#endif
diff --git a/libs/libc/inc/errno.h b/libs/libc/inc/errno.h
new file mode 100644
index 0000000..e226aba
--- /dev/null
+++ b/libs/libc/inc/errno.h
@@ -0,0 +1,52 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#ifndef ERRNO_H
+#define ERRNO_H
+
+#include <def.h>
+
+typedef s32 res;
+
+#define EOK 0 /* Success */
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define EMAX 35 /* Max errno */
+
+#ifdef userspace
+#define errno (*__errno())
+extern u32 *__errno(void);
+#endif
+
+#endif
diff --git a/libs/libc/inc/input.h b/libs/libc/inc/input.h
new file mode 100644
index 0000000..5fc7ed1
--- /dev/null
+++ b/libs/libc/inc/input.h
@@ -0,0 +1,279 @@
+// GPL-2.0 WITH Linux-syscall-note License
+// Copyright (c) 1999-2002 Vojtech Pavlik
+// Copyright (c) 2015 Hans de Goede <hdegoede@redhat.com>
+// This file is from the linux source and was modified by Marvin Borner
+
+#ifndef SCANCODE_H
+#define SCANCODE_H
+
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+
+#define KEY_ZENKAKUHANKAKU 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_RO 89
+#define KEY_KATAKANA 90
+#define KEY_HIRAGANA 91
+#define KEY_HENKAN 92
+#define KEY_KATAKANAHIRAGANA 93
+#define KEY_MUHENKAN 94
+#define KEY_KPJPCOMMA 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+#define KEY_SCALE 120
+
+#define KEY_KPCOMMA 121
+#define KEY_HANGEUL 122
+#define KEY_HANGUEL KEY_HANGEUL
+#define KEY_HANJA 123
+#define KEY_YEN 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128
+#define KEY_AGAIN 129
+#define KEY_PROPS 130
+#define KEY_UNDO 131
+#define KEY_FRONT 132
+#define KEY_COPY 133
+#define KEY_OPEN 134
+#define KEY_PASTE 135
+#define KEY_FIND 136
+#define KEY_CUT 137
+#define KEY_HELP 138
+#define KEY_MENU 139
+#define KEY_CALC 140
+#define KEY_SETUP 141
+#define KEY_SLEEP 142
+#define KEY_WAKEUP 143
+#define KEY_FILE 144
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152
+#define KEY_SCREENLOCK KEY_COFFEE
+#define KEY_ROTATE_DISPLAY 153
+#define KEY_DIRECTION KEY_ROTATE_DISPLAY
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156
+#define KEY_COMPUTER 157
+#define KEY_BACK 158
+#define KEY_FORWARD 159
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169
+#define KEY_ISO 170
+#define KEY_CONFIG 171
+#define KEY_HOMEPAGE 172
+#define KEY_REFRESH 173
+#define KEY_EXIT 174
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+#define KEY_NEW 181
+#define KEY_REDO 182
+
+#define KEY_F13 183
+#define KEY_F14 184
+#define KEY_F15 185
+#define KEY_F16 186
+#define KEY_F17 187
+#define KEY_F18 188
+#define KEY_F19 189
+#define KEY_F20 190
+#define KEY_F21 191
+#define KEY_F22 192
+#define KEY_F23 193
+#define KEY_F24 194
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_DASHBOARD 204
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206
+#define KEY_PLAY 207
+#define KEY_FASTFORWARD 208
+#define KEY_BASSBOOST 209
+#define KEY_PRINT 210
+#define KEY_HP 211
+#define KEY_CAMERA 212
+#define KEY_SOUND 213
+#define KEY_QUESTION 214
+#define KEY_EMAIL 215
+#define KEY_CHAT 216
+#define KEY_SEARCH 217
+#define KEY_CONNECT 218
+#define KEY_FINANCE 219
+#define KEY_SPORT 220
+#define KEY_SHOP 221
+#define KEY_ALTERASE 222
+#define KEY_CANCEL 223
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+#define KEY_MEDIA 226
+
+#define KEY_SWITCHVIDEOMODE 227
+#define KEY_KBDILLUMTOGGLE 228
+#define KEY_KBDILLUMDOWN 229
+#define KEY_KBDILLUMUP 230
+
+#define KEY_SEND 231
+#define KEY_REPLY 232
+#define KEY_FORWARDMAIL 233
+#define KEY_SAVE 234
+#define KEY_DOCUMENTS 235
+
+#define KEY_BATTERY 236
+
+#define KEY_BLUETOOTH 237
+#define KEY_WLAN 238
+#define KEY_UWB 239
+
+#define KEY_UNKNOWN 240
+
+#define KEY_VIDEO_NEXT 241
+#define KEY_VIDEO_PREV 242
+#define KEY_BRIGHTNESS_CYCLE 243
+#define KEY_BRIGHTNESS_AUTO 244
+#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
+#define KEY_DISPLAY_OFF 245
+
+#define KEY_WWAN 246
+#define KEY_WIMAX KEY_WWAN
+#define KEY_RFKILL 247
+
+#define KEY_MICMUTE 248
+
+#define KEY_NUMERIC(code) ((code) >= KEY_1 && (code) <= KEY_0)
+#define KEY_ALPHABETIC(code) \
+ (((code) >= KEY_Q && (code) <= KEY_P) || ((code) >= KEY_A && (code) <= KEY_L) || \
+ ((code) >= KEY_Z && (code) <= KEY_M))
+#define KEY_ALPHANUMERIC(code) (KEY_NUMERIC((code)) || KEY_ALPHABETIC((code)))
+
+typedef int fortytwo;
+
+#endif
diff --git a/libs/libc/inc/ioctl.h b/libs/libc/inc/ioctl.h
new file mode 100644
index 0000000..c3eec56
--- /dev/null
+++ b/libs/libc/inc/ioctl.h
@@ -0,0 +1,11 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#ifndef IOCTL
+#define IOCTL
+
+// FB interface
+#define IO_FB_GET 0
+
+int ioctl_is_awesome; // GCC is not
+
+#endif
diff --git a/libs/libc/inc/list.h b/libs/libc/inc/list.h
new file mode 100644
index 0000000..0b82b48
--- /dev/null
+++ b/libs/libc/inc/list.h
@@ -0,0 +1,29 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef LIST_H
+#define LIST_H
+
+#include <def.h>
+
+struct list {
+ struct node *head;
+};
+
+struct node {
+ void *data;
+ int nonce;
+ struct node *next;
+ struct node *prev;
+};
+
+struct list *list_new(void);
+void list_destroy(struct list *list);
+/* struct node *list_new_node(); */ // TODO: Make node-specific things static/private?
+/* void list_add_node(struct list *list, struct node *node); */
+struct node *list_add(struct list *list, void *data);
+struct list *list_remove(struct list *list, struct node *node);
+struct node *list_last(struct list *list);
+struct list *list_swap(struct list *list, struct node *a, struct node *b);
+struct node *list_first_data(struct list *list, void *data);
+
+#endif
diff --git a/libs/libc/inc/math.h b/libs/libc/inc/math.h
new file mode 100644
index 0000000..82f431f
--- /dev/null
+++ b/libs/libc/inc/math.h
@@ -0,0 +1,8 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef MATH_H
+#define MATH_H
+
+int pow(int base, int exp);
+
+#endif
diff --git a/libs/libc/inc/mem.h b/libs/libc/inc/mem.h
new file mode 100644
index 0000000..ec00628
--- /dev/null
+++ b/libs/libc/inc/mem.h
@@ -0,0 +1,29 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef MEM_H
+#define MEM_H
+
+#include <def.h>
+
+void *malloc_debug(u32 size, const char *file, int line, const char *func, const char *inp);
+void free_debug(void *ptr, const char *file, int line, const char *func, const char *inp);
+#define malloc(size) malloc_debug((u32)(size), __FILE__, __LINE__, __func__, #size)
+#define free(ptr) free_debug((void *)(ptr), __FILE__, __LINE__, __func__, #ptr)
+void *realloc(void *ptr, u32 size);
+void *zalloc(u32 size);
+
+#ifdef kernel
+#define STACK_START 0x00500000 // Defined it bootloader
+#define STACK_SIZE 0x1000 // idk
+#elif defined(userspace)
+#else
+#error "No lib target specified. Please use -Dkernel or -Duserspace"
+#endif
+
+void *memcpy(void *dest, const void *src, u32 n);
+void *memset(void *dest, int val, u32 n);
+void *memchr(void *src, int c, u32 n);
+int memcmp(const void *s1, const void *s2, u32 n);
+int mememp(const u8 *buf, u32 n);
+
+#endif
diff --git a/libs/libc/inc/print.h b/libs/libc/inc/print.h
new file mode 100644
index 0000000..58b5dc6
--- /dev/null
+++ b/libs/libc/inc/print.h
@@ -0,0 +1,27 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef PRINT_H
+#define PRINT_H
+
+#include "arg.h"
+#include <def.h>
+
+int printf(const char *format, ...);
+int vprintf(const char *format, va_list ap);
+int sprintf(char *str, const char *format, ...);
+int vsprintf(char *str, const char *format, va_list ap);
+int print(const char *str);
+NORETURN void panic(const char *format, ...);
+
+#ifdef userspace
+int vfprintf(const char *path, const char *format, va_list ap);
+int fprintf(const char *path, const char *format, ...);
+int log(const char *format, ...);
+int err(int code, const char *format, ...);
+#else
+#include <proc.h>
+int print_app(enum stream_defaults id, const char *proc_name, const char *str);
+void print_trace(u32 count);
+#endif
+
+#endif
diff --git a/libs/libc/inc/random.h b/libs/libc/inc/random.h
new file mode 100644
index 0000000..a82524c
--- /dev/null
+++ b/libs/libc/inc/random.h
@@ -0,0 +1,14 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#include <def.h>
+
+void srand(u32 seed);
+u32 rdrand(void);
+u32 rdseed(void);
+u32 rand(void);
+char *randstr(u32 size);
+
+#endif
diff --git a/libs/libc/inc/socket.h b/libs/libc/inc/socket.h
new file mode 100644
index 0000000..18bc316
--- /dev/null
+++ b/libs/libc/inc/socket.h
@@ -0,0 +1,38 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef SOCKET_H
+#define SOCKET_H
+
+#include <def.h>
+#include <list.h>
+
+// TODO: Use actual socket types (stream etc)
+enum socket_type { S_TCP, S_UDP };
+enum socket_state { S_CONNECTING, S_CONNECTED, S_OPEN, S_CLOSING, S_CLOSED, S_FAILED };
+
+struct tcp_socket {
+ u32 seq_no;
+ u32 ack_no;
+ u32 state;
+};
+
+struct socket_data {
+ u8 *data;
+ u32 length;
+};
+
+struct socket {
+ u32 pid;
+ u32 ip_addr;
+ u32 dst_port;
+ u32 src_port;
+ enum socket_state state;
+ enum socket_type type;
+ struct list *packets;
+ union {
+ struct tcp_socket tcp;
+ /* struct udp_socket udp; */
+ } prot;
+};
+
+#endif
diff --git a/libs/libc/inc/stack.h b/libs/libc/inc/stack.h
new file mode 100644
index 0000000..f5ad52b
--- /dev/null
+++ b/libs/libc/inc/stack.h
@@ -0,0 +1,28 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef STACK_H
+#define STACK_H
+
+#include <def.h>
+
+struct stack_node {
+ void *data;
+ int nonce;
+ struct stack_node *next;
+ struct stack_node *prev;
+};
+
+struct stack {
+ struct stack_node *tail;
+};
+
+struct stack *stack_new(void);
+void stack_destroy(struct stack *stack);
+u32 stack_empty(struct stack *stack);
+u32 stack_push_bot(struct stack *stack, void *data);
+u32 stack_push(struct stack *stack, void *data);
+void *stack_pop(struct stack *stack);
+void *stack_peek(struct stack *stack);
+void stack_clear(struct stack *stack);
+
+#endif
diff --git a/libs/libc/inc/str.h b/libs/libc/inc/str.h
new file mode 100644
index 0000000..d0a521f
--- /dev/null
+++ b/libs/libc/inc/str.h
@@ -0,0 +1,22 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#ifndef STR_H
+#define STR_H
+
+#include <def.h>
+
+u32 strlen(const char *s);
+char *strcpy(char *dst, const char *src);
+char *strncpy(char *dst, const char *src, u32 n);
+char *strchr(char *s, int c);
+char *strrchr(char *s, int c);
+char *strcat(char *dst, const char *src);
+char *strncat(char *dst, const char *src, u32 n);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, u32 n);
+char *strinv(char *s);
+char *strdup(const char *s);
+
+const char *strerror(u32 err);
+
+#endif
diff --git a/libs/libc/inc/sys.h b/libs/libc/inc/sys.h
new file mode 100644
index 0000000..19fb3ee
--- /dev/null
+++ b/libs/libc/inc/sys.h
@@ -0,0 +1,130 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// Syscall implementation
+
+#ifndef SYS_H
+#define SYS_H
+
+#include <def.h>
+#include <errno.h>
+
+#define KEYBOARD_MAGIC 0x555555
+#define MOUSE_MAGIC 0xaaaaaa
+
+#define SYS_BOOT_MAGIC 0x18122002
+#define SYS_BOOT_REBOOT 0xeeb007
+#define SYS_BOOT_SHUTDOWN 0xdead
+
+enum sys {
+ SYS_LOOP, // To infinity and beyond (debug)!
+ SYS_ALLOC, // Allocate memory
+ SYS_SHACCESS, // Access shared memory
+ SYS_FREE, // Free memory
+ SYS_STAT, // Get file information
+ SYS_READ, // Read file
+ SYS_WRITE, // Write to file
+ SYS_IOCTL, // Interact with a file/device
+ SYS_POLL, // Wait for multiple files
+ SYS_EXEC, // Execute path
+ SYS_EXIT, // Exit current process
+ SYS_BOOT, // Boot functions (e.g. reboot/shutdown)
+ SYS_YIELD, // Switch to next process
+ SYS_TIME, // Get kernel time
+ /* SYS_NET_OPEN, // Open network socket */
+ /* SYS_NET_CLOSE, // Close network socket */
+ /* SYS_NET_CONNECT, // Connect to destination */
+ /* SYS_NET_SEND, // Send to socket */
+ /* SYS_NET_RECEIVE, // Receive data from socket */
+};
+
+struct event_keyboard {
+ u32 magic;
+ u32 scancode;
+ u8 press;
+};
+
+struct event_mouse {
+ u32 magic;
+ s32 diff_x;
+ s32 diff_y;
+ u8 but1;
+ u8 but2;
+ u8 but3;
+};
+
+struct stat {
+ u32 dev_id;
+ u32 mode;
+ u32 uid;
+ u32 gid;
+ u32 size;
+};
+
+#if defined(userspace)
+
+/**
+ * Syscall wrappers
+ */
+
+void loop(void);
+void exit(s32 status);
+res read(const char *path, void *buf, u32 offset, u32 count);
+res write(const char *path, const void *buf, u32 offset, u32 count);
+res ioctl(const char *path, ...);
+res stat(const char *path, struct stat *buf);
+res poll(const char **files);
+res exec(const char *path, ...);
+res yield(void);
+res boot(u32 cmd);
+u32 time(void);
+
+res sys_alloc(u32 size, u32 *addr);
+res sys_free(void *ptr);
+res shalloc(u32 size, u32 *addr, u32 *id);
+res shaccess(u32 id, u32 *addr, u32 *size);
+
+static inline u32 getpid(void)
+{
+ static u32 buf = 0;
+ if (buf)
+ return buf;
+ read("/proc/self/pid", &buf, 0, sizeof(buf));
+ return buf;
+}
+
+#include <print.h>
+#include <str.h>
+static inline u32 pidof(const char *name)
+{
+ u32 curr = 1;
+ char buf[32] = { 0 }, path[32] = { 0 };
+ while (curr < 1000) { // Max pid??
+ if (sprintf(path, "/proc/%d/name", curr) > 0 && read(path, buf, 0, 32) > 0)
+ if (!strcmp(name, buf))
+ return curr;
+
+ curr++;
+ }
+
+ return -1;
+}
+
+// Simple read wrapper
+#include <mem.h>
+static inline void *sread(const char *path)
+{
+ struct stat s = { 0 };
+ if (stat(path, &s) != 0 || !s.size)
+ return NULL;
+ void *buf = malloc(s.size);
+ read(path, buf, 0, s.size);
+ return buf;
+}
+
+/**
+ * At exit
+ */
+
+void atexit(void (*func)(void));
+
+#endif
+#endif
diff --git a/libs/libc/inc/vec.h b/libs/libc/inc/vec.h
new file mode 100644
index 0000000..a036931
--- /dev/null
+++ b/libs/libc/inc/vec.h
@@ -0,0 +1,36 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#ifndef VEC_H
+#define VEC_H
+
+#include <def.h>
+
+typedef struct vec2 {
+ u32 x, y;
+} vec2;
+
+typedef struct vec3 {
+ u32 x, y, z;
+} vec3;
+
+#define vec2(x, y) ((vec2){ (x), (y) })
+#define vec2to3(a, z) ((vec3){ a.x, a.y, (z) })
+#define vec2_add(a, b) ((vec2){ a.x + b.x, a.y + b.y })
+#define vec2_sub(a, b) ((vec2){ a.x - b.x, a.y - b.y })
+#define vec2_mul(a, b) ((vec2){ a.x * (b), a.y * (b) })
+#define vec2_div(a, b) ((vec2){ a.x / (b), a.y / (b) })
+#define vec2_dot(a, b) ((u32)(a.x * b.x + a.y * b.y))
+#define vec2_eq(a, b) (a.x == b.x && a.y == b.y)
+
+#define vec3(x, y, z) ((vec3){ (x), (y), (z) })
+#define vec3to2(a) ((vec2){ a.x, a.y })
+#define vec3_add(a, b) ((vec3){ a.x + b.x, a.y + b.y, a.z + b.z })
+#define vec3_sub(a, b) ((vec3){ a.x - b.x, a.y - b.y, a.z - b.z })
+#define vec3_mul(a, b) ((vec3){ a.x * (b), a.y * (b), a.z * (b) })
+#define vec3_div(a, b) ((vec3){ a.x / (b), a.y / (b), a.z / (b) })
+#define vec3_dot(a, b) ((u32)(a.x * b.x + a.y * b.y + a.z * b.z))
+#define vec3_eq(a, b) (a.x == b.x && a.y == b.y && a.z == c.z)
+#define vec3_cross(a, b) \
+ ((vec3){ a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x })
+
+#endif
diff --git a/libs/libc/list.c b/libs/libc/list.c
new file mode 100644
index 0000000..c86b23d
--- /dev/null
+++ b/libs/libc/list.c
@@ -0,0 +1,138 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <def.h>
+#include <list.h>
+#include <mem.h>
+
+static int nonce = 0;
+
+struct list *list_new(void)
+{
+ struct list *list = malloc(sizeof(*list));
+ list->head = NULL;
+ return list;
+}
+
+void list_destroy(struct list *list)
+{
+ if (!list)
+ return;
+ struct node *iterator = list->head;
+ while (iterator != NULL) {
+ if (iterator->next == NULL) {
+ free(iterator);
+ break;
+ }
+ iterator = iterator->next;
+ free(iterator->prev);
+ }
+ list->head = NULL;
+ free(list);
+ list = NULL;
+}
+
+static struct node *list_new_node(void)
+{
+ struct node *node = malloc(sizeof(*node));
+ node->data = NULL;
+ node->prev = NULL;
+ node->next = NULL;
+ node->nonce = nonce++;
+ return node;
+}
+
+static struct node *list_add_node(struct list *list, struct node *node)
+{
+ if (!list || !node)
+ return NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ return list->head;
+ }
+
+ struct node *iterator = list->head;
+ while (iterator != NULL) {
+ if (iterator->next == NULL) {
+ iterator->next = node;
+ node->prev = iterator;
+ break;
+ }
+ iterator = iterator->next;
+ }
+ return node;
+}
+
+struct node *list_last(struct list *list)
+{
+ if (!list || !list->head)
+ return NULL;
+
+ struct node *iterator = list->head;
+ while (iterator != NULL) {
+ if (iterator->next == NULL)
+ return iterator;
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+struct node *list_first_data(struct list *list, void *data)
+{
+ if (!list || !list->head || !data)
+ return NULL;
+
+ struct node *iterator = list->head;
+ while (iterator != NULL) {
+ if (iterator->data == data)
+ return iterator;
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+// TODO: Actually swap the nodes, not the data
+struct list *list_swap(struct list *list, struct node *a, struct node *b)
+{
+ if (!list || !list->head || !a || !b)
+ return NULL;
+
+ void *tmp = a->data;
+ a->data = b->data;
+ b->data = tmp;
+
+ return list;
+}
+
+struct node *list_add(struct list *list, void *data)
+{
+ struct node *node = list_new_node();
+ node->data = data;
+ return list_add_node(list, node);
+}
+
+// Maybe list_remove_node?
+struct list *list_remove(struct list *list, struct node *node)
+{
+ if (!list || !list->head || !node)
+ return NULL;
+
+ if (list->head == node) {
+ list->head = list->head->next;
+ return list;
+ }
+
+ struct node *iterator = list->head->next;
+ while (iterator != node) {
+ iterator = iterator->next;
+ if (iterator == NULL)
+ return NULL;
+ }
+
+ iterator->prev->next = iterator->next;
+ if (iterator->next)
+ iterator->next->prev = iterator->prev;
+ return list;
+}
diff --git a/libs/libc/math.c b/libs/libc/math.c
new file mode 100644
index 0000000..c8142b5
--- /dev/null
+++ b/libs/libc/math.c
@@ -0,0 +1,17 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <math.h>
+
+int pow(int base, int exp)
+{
+ if (exp < 0)
+ return 0;
+
+ if (!exp)
+ return 1;
+
+ int ret = base;
+ for (int i = 1; i < exp; i++)
+ ret *= base;
+ return ret;
+}
diff --git a/libs/libc/mem.c b/libs/libc/mem.c
new file mode 100644
index 0000000..95242e4
--- /dev/null
+++ b/libs/libc/mem.c
@@ -0,0 +1,121 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <assert.h>
+#include <def.h>
+#include <mem.h>
+#include <sys.h>
+
+void *memcpy(void *dest, const void *src, u32 n)
+{
+#ifdef userspace
+ // Inspired by Jeko at osdev
+ u8 *dest_byte = dest;
+ const u8 *src_byte = src;
+ for (u32 i = 0; i < n / 16; i++) {
+ __asm__ volatile("movups (%0), %%xmm0\n"
+ "movntdq %%xmm0, (%1)\n" ::"r"(src_byte),
+ "r"(dest_byte)
+ : "memory");
+
+ src_byte += 16;
+ dest_byte += 16;
+ }
+
+ if (n & 7) {
+ n = n & 7;
+
+ int d0, d1, d2;
+ __asm__ volatile("rep ; movsl\n\t"
+ "testb $2,%b4\n\t"
+ "je 1f\n\t"
+ "movsw\n"
+ "1:\ttestb $1,%b4\n\t"
+ "je 2f\n\t"
+ "movsb\n"
+ "2:"
+ : "=&c"(d0), "=&D"(d1), "=&S"(d2)
+ : "0"(n / 4), "q"(n), "1"((long)dest_byte), "2"((long)src_byte)
+ : "memory");
+ }
+ return dest_byte;
+#else
+ // Inspired by jgraef at osdev
+ u32 num_dwords = n / 4;
+ u32 num_bytes = n % 4;
+ u32 *dest32 = (u32 *)dest;
+ const u32 *src32 = (const u32 *)src;
+ u8 *dest8 = ((u8 *)dest) + num_dwords * 4;
+ const u8 *src8 = ((const u8 *)src) + num_dwords * 4;
+
+ // TODO: What's faster?
+ __asm__ volatile("rep movsl\n"
+ : "=S"(src32), "=D"(dest32), "=c"(num_dwords)
+ : "S"(src32), "D"(dest32), "c"(num_dwords)
+ : "memory");
+
+ /* for (u32 i = 0; i < num_dwords; i++) { */
+ /* dest32[i] = src32[i]; */
+ /* } */
+
+ for (u32 i = 0; i < num_bytes; i++) {
+ dest8[i] = src8[i];
+ }
+ return dest;
+#endif
+}
+
+void *memset(void *dest, int val, u32 n)
+{
+ u32 uval = val;
+ u32 num_dwords = n / 4;
+ u32 num_bytes = n % 4;
+ u32 *dest32 = (u32 *)dest;
+ u8 *dest8 = ((u8 *)dest) + num_dwords * 4;
+ u8 val8 = (u8)val;
+ u32 val32 = uval | (uval << 8) | (uval << 16) | (uval << 24);
+
+ // TODO: What's faster?
+ __asm__ volatile("rep stosl\n"
+ : "=D"(dest32), "=c"(num_dwords)
+ : "D"(dest32), "c"(num_dwords), "a"(val32)
+ : "memory");
+
+ /* for (u32 i = 0; i < num_dwords; i++) { */
+ /* dest32[i] = val32; */
+ /* } */
+
+ for (u32 i = 0; i < num_bytes; i++) {
+ dest8[i] = val8;
+ }
+ return dest;
+}
+
+void *memchr(void *src, int c, u32 n)
+{
+ u8 *s = (u8 *)src;
+
+ while (n-- > 0) {
+ if (*s == c)
+ return s;
+ s++;
+ }
+ return NULL;
+}
+
+int memcmp(const void *s1, const void *s2, u32 n)
+{
+ const u8 *a = (const u8 *)s1;
+ const u8 *b = (const u8 *)s2;
+ for (u32 i = 0; i < n; i++) {
+ if (a[i] < b[i])
+ return -1;
+ else if (b[i] < a[i])
+ return 1;
+ }
+ return 0;
+}
+
+int mememp(const u8 *buf, u32 n)
+{
+ return buf[0] == 0 && !memcmp(buf, buf + 1, n - 1);
+}
diff --git a/libs/libc/print.c b/libs/libc/print.c
new file mode 100644
index 0000000..2422fed
--- /dev/null
+++ b/libs/libc/print.c
@@ -0,0 +1,257 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <arg.h>
+#include <assert.h>
+#include <conv.h>
+#include <cpu.h>
+#include <def.h>
+#include <mem.h>
+#include <str.h>
+
+static void append(char *dest, char *src, int index)
+{
+ for (u32 i = index; i < strlen(src) + index; i++)
+ dest[i] = src[i - index];
+ dest[index + strlen(src)] = 0;
+}
+
+int vsprintf(char *str, const char *format, va_list ap)
+{
+ u8 ready_to_format = 0;
+
+ int i = 0;
+ char buf = 0;
+ char format_buffer[20] = { '\0' };
+
+ for (; *format; format++) {
+ if (ready_to_format) {
+ ready_to_format = 0;
+
+ if (*format == '%') {
+ str[i] = '%';
+ continue;
+ }
+
+ buf = *format;
+
+ // TODO: Improve this repetitive code
+ if (buf == 's') {
+ char *string = va_arg(ap, char *);
+ assert(string);
+ append(str, string, i);
+ i = strlen(str);
+ } else if (buf == 'x') {
+ conv_base(va_arg(ap, u32), format_buffer, 16, 0);
+ append(str, format_buffer, i);
+ i = strlen(str);
+ } else if (buf == 'd' || buf == 'i') {
+ conv_base(va_arg(ap, s32), format_buffer, 10, 1);
+ append(str, format_buffer, i);
+ i = strlen(str);
+ } else if (buf == 'u') {
+ conv_base(va_arg(ap, u32), format_buffer, 10, 0);
+ append(str, format_buffer, i);
+ i = strlen(str);
+ } else if (buf == 'o') {
+ conv_base(va_arg(ap, u32), format_buffer, 8, 0);
+ append(str, format_buffer, i);
+ i = strlen(str);
+ } else if (buf == 'b') {
+ conv_base(va_arg(ap, u32), format_buffer, 2, 0);
+ append(str, format_buffer, i);
+ i = strlen(str);
+ } else if (buf == 'c') {
+ str[i] = (char)va_arg(ap, int);
+ i++;
+ } else {
+ assert(0);
+ }
+ } else {
+ if (*format == '%')
+ ready_to_format = 1;
+ else {
+ str[i] = *format;
+ i++;
+ }
+ }
+
+ format_buffer[0] = '\0';
+ }
+
+ return strlen(str);
+}
+
+int sprintf(char *str, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int len = vsprintf(str, format, ap);
+ va_end(ap);
+
+ return len;
+}
+
+#ifdef userspace
+
+#include <sys.h>
+#define PATH_OUT "/proc/self/io/out"
+#define PATH_LOG "/proc/self/io/log"
+#define PATH_ERR "/proc/self/io/err"
+
+int vprintf(const char *format, va_list ap)
+{
+ return vfprintf(PATH_OUT, format, ap);
+}
+
+int vfprintf(const char *path, const char *format, va_list ap)
+{
+ char buf[1024] = { 0 };
+ int len = vsprintf(buf, format, ap);
+ return write(path, buf, 0, len);
+}
+
+int fprintf(const char *path, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int len = vfprintf(path, format, ap);
+ va_end(ap);
+
+ return len;
+}
+
+int printf(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int len = vprintf(format, ap);
+ va_end(ap);
+
+ return len;
+}
+
+int log(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int len = vfprintf(PATH_LOG, format, ap);
+ va_end(ap);
+
+ return len;
+}
+
+int err(int code, const char *format, ...)
+{
+ if (errno != EOK)
+ log("ERRNO: %d (%s)\n", errno, strerror(errno));
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(PATH_ERR, format, ap);
+ va_end(ap);
+ exit(code);
+ return -1;
+}
+
+int print(const char *str)
+{
+ return write(PATH_OUT, str, 0, strlen(str));
+}
+
+#else
+
+// The kernel prints everything into the serial console
+
+#include <mm.h>
+#include <proc.h>
+#include <serial.h>
+
+#define RED "\x1B[1;31m"
+#define GRN "\x1B[1;32m"
+#define YEL "\x1B[1;33m"
+#define BLU "\x1B[1;34m"
+#define MAG "\x1B[1;35m"
+#define CYN "\x1B[1;36m"
+#define WHT "\x1B[1;37m"
+#define RES "\x1B[0m"
+
+static void print_kernel(const char *str)
+{
+ serial_print(RED);
+ serial_print("[KER] ");
+ serial_print(str);
+ serial_print(RES);
+}
+
+int vprintf(const char *format, va_list ap)
+{
+ char buf[1024] = { 0 };
+ int len = vsprintf(buf, format, ap);
+ print_kernel(buf);
+ return len;
+}
+
+int printf(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int len = vprintf(format, ap);
+ va_end(ap);
+
+ return len;
+}
+
+int print_app(enum stream_defaults id, const char *proc_name, const char *str)
+{
+ if (id == STREAM_LOG)
+ serial_print(CYN "[LOG] to ");
+ else if (id == STREAM_ERR)
+ serial_print(YEL "[ERR] to ");
+ serial_print(proc_name);
+ serial_print(": ");
+ serial_print(str);
+ serial_print(RES);
+ return 1;
+}
+
+int print(const char *str)
+{
+ print_kernel(str);
+ return strlen(str);
+}
+
+void print_trace(u32 count)
+{
+ struct frame {
+ struct frame *ebp;
+ u32 eip;
+ } * stk;
+ __asm__ volatile("movl %%ebp, %0;" : "=r"(stk));
+ print("EBP\tEIP\n");
+ for (u32 i = 0; stk && i < count; i++) {
+ /* u32 eip = memory_valid((void *)stk->eip) ? stk->eip : stk->eip + 64; */
+ /* printf("0x%x\t0x%x\n", stk->ebp, eip); */
+ printf("0x%x\t0x%x\n", stk->ebp, stk->eip);
+ stk = stk->ebp;
+ }
+}
+
+#endif
+
+NORETURN void panic(const char *format, ...)
+{
+ char buf[1024] = { 0 };
+ va_list ap;
+ va_start(ap, format);
+ vsprintf(buf, format, ap);
+ va_end(ap);
+#ifdef kernel
+ print("--- DON'T PANIC! ---\n");
+ print(buf);
+ print_trace(5);
+ loop();
+#else
+ err(1, buf);
+#endif
+ while (1)
+ ;
+}
diff --git a/libs/libc/random.c b/libs/libc/random.c
new file mode 100644
index 0000000..2801029
--- /dev/null
+++ b/libs/libc/random.c
@@ -0,0 +1,71 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <cpu.h>
+#include <def.h>
+#include <mem.h>
+#include <random.h>
+
+static u32 g_seed = 1;
+
+void srand(u32 seed)
+{
+ g_seed = seed;
+}
+
+u32 rdrand(void)
+{
+#ifdef kernel
+ if (!cpu_has_cfeature(CPUID_FEAT_ECX_RDRND))
+ return rand();
+
+ u32 rd;
+ __asm__ volatile("1:\n"
+ "rdrand %0\n"
+ "jnc 1b\n"
+ : "=r"(rd));
+ return rd;
+#else
+ return rand();
+#endif
+}
+
+u32 rdseed(void)
+{
+#ifdef kernel
+ if (!cpu_has_cfeature(CPUID_FEAT_ECX_RDRND))
+ return rand();
+
+ u32 rd;
+ __asm__ volatile("1:\n"
+ "rdseed %0\n"
+ "jnc 1b\n"
+ : "=r"(rd));
+ return rd;
+#else
+ return rand();
+#endif
+}
+
+u32 rand(void)
+{
+ g_seed = g_seed * 1103515245 + 12345;
+ return (g_seed >> 16) & 0x7FFF;
+}
+
+char *randstr(u32 size)
+{
+ if (!size)
+ return NULL;
+
+ char *buf = malloc(size + 1);
+ const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+ size--;
+ for (u32 i = 0; i < size; i++) {
+ int key = rand() % (sizeof(charset) - 1);
+ buf[i] = charset[key];
+ }
+ buf[size] = '\0';
+
+ return buf;
+}
diff --git a/libs/libc/sanitize.c b/libs/libc/sanitize.c
new file mode 100644
index 0000000..02eef84
--- /dev/null
+++ b/libs/libc/sanitize.c
@@ -0,0 +1,228 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+// Detect stack overflows and other bugs
+
+#include <def.h>
+#include <print.h>
+
+/**
+ * Stack protector
+ */
+
+#define STACK_CHK_GUARD 0xdeadbeef
+
+u32 __stack_chk_guard = STACK_CHK_GUARD;
+
+void __stack_chk_fail(void);
+NORETURN void __stack_chk_fail(void)
+{
+ panic("FATAL: Stack smashing detected\n");
+}
+
+void __stack_chk_fail_local(void);
+NORETURN void __stack_chk_fail_local(void)
+{
+ panic("FATAL: Local stack smashing detected\n");
+}
+
+/**
+ * UBSan
+ * TODO: Fix san-paths for userspace (maybe due to -fPIE?)
+ */
+
+#define is_aligned(value, alignment) !(value & (alignment - 1))
+
+struct source_location {
+ const char *file;
+ u32 line;
+ u32 column;
+};
+
+struct type_descriptor {
+ u16 kind;
+ u16 info;
+ char name[];
+};
+
+struct type_mismatch {
+ struct source_location location;
+ struct type_descriptor *type;
+ u8 alignment;
+ u8 type_check_kind;
+};
+
+struct overflow {
+ struct source_location location;
+ struct type_descriptor *type;
+};
+
+struct out_of_bounds {
+ struct source_location location;
+ struct type_descriptor *left_type;
+ struct type_descriptor *right_type;
+};
+
+void __ubsan_handle_load_invalid_value(void);
+void __ubsan_handle_load_invalid_value(void)
+{
+ panic("UBSAN: load-invalid-value\n");
+}
+
+void __ubsan_handle_nonnull_arg(void);
+void __ubsan_handle_nonnull_arg(void)
+{
+ panic("UBSAN: nonnull-arg\n");
+}
+
+void __ubsan_handle_nullability_arg(void);
+void __ubsan_handle_nullability_arg(void)
+{
+ panic("UBSAN: nullability-arg\n");
+}
+
+void __ubsan_handle_nonnull_return_v1(void);
+void __ubsan_handle_nonnull_return_v1(void)
+{
+ panic("UBSAN: nonnull-return-v1\n");
+}
+
+void __ubsan_handle_nullability_return_v1(void);
+void __ubsan_handle_nullability_return_v1(void)
+{
+ panic("UBSAN: nullability-return-v1\n");
+}
+
+void __ubsan_handle_vla_bound_not_positive(void);
+void __ubsan_handle_vla_bound_not_positive(void)
+{
+ panic("UBSAN: vla-bound-not-positive\n");
+}
+
+void __ubsan_handle_add_overflow(struct overflow *data, void *left, void *right);
+void __ubsan_handle_add_overflow(struct overflow *data, void *left, void *right)
+{
+ UNUSED(left);
+ UNUSED(right);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: add-overflow [type: %s]\n", loc->file, loc->line, data->type->name);
+}
+
+void __ubsan_handle_sub_overflow(struct overflow *data, void *left, void *right);
+void __ubsan_handle_sub_overflow(struct overflow *data, void *left, void *right)
+{
+ UNUSED(left);
+ UNUSED(right);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: sub-overflow [type: %s]\n", loc->file, loc->line, data->type->name);
+}
+
+void __ubsan_handle_negate_overflow(struct overflow *data, void *left, void *right);
+void __ubsan_handle_negate_overflow(struct overflow *data, void *left, void *right)
+{
+ UNUSED(left);
+ UNUSED(right);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: negate-overflow [type: %s]\n", loc->file, loc->line, data->type->name);
+}
+
+void __ubsan_handle_mul_overflow(struct overflow *data, void *left, void *right);
+void __ubsan_handle_mul_overflow(struct overflow *data, void *left, void *right)
+{
+ UNUSED(left);
+ UNUSED(right);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: mul-overflow [type: %s]\n", loc->file, loc->line, data->type->name);
+}
+
+void __ubsan_handle_shift_out_of_bounds(struct overflow *data, void *left, void *right);
+void __ubsan_handle_shift_out_of_bounds(struct overflow *data, void *left, void *right)
+{
+ UNUSED(left);
+ UNUSED(right);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: shift-out-of-bounds [type: %s]\n", loc->file, loc->line,
+ data->type->name);
+}
+
+void __ubsan_handle_divrem_overflow(struct overflow *data, void *left, void *right);
+void __ubsan_handle_divrem_overflow(struct overflow *data, void *left, void *right)
+{
+ UNUSED(left);
+ UNUSED(right);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: divrem-overflow (probably div-by-zero) [type: %s]\n", loc->file,
+ loc->line, data->type->name);
+}
+
+void __ubsan_handle_out_of_bounds(struct out_of_bounds *data, void *value);
+void __ubsan_handle_out_of_bounds(struct out_of_bounds *data, void *value)
+{
+ UNUSED(value);
+ struct source_location *loc = &data->location;
+ panic("%s:%d: UBSAN: out-of-bounds\n", loc->file, loc->line);
+}
+
+void __ubsan_handle_type_mismatch_v1(struct type_mismatch *data, u32 ptr);
+void __ubsan_handle_type_mismatch_v1(struct type_mismatch *data, u32 ptr)
+{
+ static const char *kinds[] = {
+ "Load of",
+ "Store to",
+ "Reference binding to",
+ "Member access within",
+ "Member call on",
+ "Constructor call on",
+ "Downcast of",
+ "Downcast of",
+ "Upcast of",
+ "Cast to virtual base of",
+ "Nonnull binding to",
+ "Dynamic operation on",
+ };
+
+ struct source_location *loc = &data->location;
+ const char *msg = "";
+ if (ptr == 0) {
+ msg = "null pointer";
+ } else if (data->alignment != 0 && is_aligned(ptr, data->alignment))
+ msg = "misaligned memory address";
+ else
+ msg = "address with insufficient space";
+ panic("%s:%d: UBSAN: %s %s [type: %s; addr: 0x%x; align: %d]\n", loc->file, loc->line,
+ kinds[data->type_check_kind], msg, data->type->name, ptr, data->alignment);
+}
+
+void __ubsan_handle_alignment_assumption(void);
+void __ubsan_handle_alignment_assumption(void)
+{
+ panic("UBSAN: alignment-assumption\n");
+}
+
+void __ubsan_handle_builtin_unreachable(void);
+void __ubsan_handle_builtin_unreachable(void)
+{
+ panic("UBSAN: builtin-unreachable\n");
+}
+
+void __ubsan_handle_missing_return(void);
+void __ubsan_handle_missing_return(void)
+{
+ panic("UBSAN: missing-return\n");
+}
+
+void __ubsan_handle_implicit_conversion(void);
+void __ubsan_handle_implicit_conversion(void)
+{
+ panic("UBSAN: implicit-conversion\n");
+}
+
+void __ubsan_handle_invalid_builtin(void);
+void __ubsan_handle_invalid_builtin(void)
+{
+ panic("UBSAN: invalid-builtin\n");
+}
+
+void __ubsan_handle_pointer_overflow(void);
+void __ubsan_handle_pointer_overflow(void)
+{
+ panic("UBSAN: pointer-overflow\n");
+}
diff --git a/libs/libc/stack.c b/libs/libc/stack.c
new file mode 100644
index 0000000..0cbb69d
--- /dev/null
+++ b/libs/libc/stack.c
@@ -0,0 +1,126 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <def.h>
+#include <mem.h>
+#include <stack.h>
+
+static int nonce = 0;
+
+struct stack *stack_new(void)
+{
+ struct stack *stack = malloc(sizeof(*stack));
+ stack->tail = NULL;
+ return stack;
+}
+
+void stack_destroy(struct stack *stack)
+{
+ struct stack_node *iterator = stack->tail;
+ while (iterator) {
+ if (!iterator->prev) {
+ free(iterator);
+ break;
+ }
+ iterator = iterator->prev;
+ free(iterator->next);
+ }
+ stack->tail = NULL;
+ free(stack);
+ stack = NULL;
+}
+
+static struct stack_node *stack_new_node(void)
+{
+ struct stack_node *node = malloc(sizeof(*node));
+ node->data = NULL;
+ node->prev = NULL;
+ node->next = NULL;
+ node->nonce = nonce++;
+ return node;
+}
+
+static u32 stack_push_bot_node(struct stack *stack, struct stack_node *node)
+{
+ if (!stack || !node)
+ return 0;
+
+ if (stack->tail) {
+ struct stack_node *iterator = stack->tail;
+ while (iterator) {
+ if (!iterator->prev)
+ break;
+ iterator = iterator->prev;
+ }
+ iterator->prev = node;
+ node->next = iterator;
+ } else {
+ stack->tail = node;
+ }
+
+ return 1;
+}
+
+static u32 stack_push_node(struct stack *stack, struct stack_node *node)
+{
+ if (!stack || !node)
+ return 0;
+
+ if (stack->tail) {
+ stack->tail->next = node;
+ node->prev = stack->tail;
+ stack->tail = node;
+ } else {
+ stack->tail = node;
+ }
+
+ return 1;
+}
+
+u32 stack_empty(struct stack *stack)
+{
+ return !stack->tail;
+}
+
+u32 stack_push_bot(struct stack *stack, void *data)
+{
+ struct stack_node *node = stack_new_node();
+ node->data = data;
+ return stack_push_bot_node(stack, node);
+}
+
+u32 stack_push(struct stack *stack, void *data)
+{
+ struct stack_node *node = stack_new_node();
+ node->data = data;
+ return stack_push_node(stack, node);
+}
+
+void *stack_pop(struct stack *stack)
+{
+ if (!stack || !stack->tail)
+ return NULL;
+
+ struct stack_node *prev = stack->tail;
+
+ if (stack->tail->prev)
+ stack->tail->prev->next = NULL;
+ stack->tail = stack->tail->prev;
+
+ void *data = prev->data;
+ free(prev);
+ return data;
+}
+
+void *stack_peek(struct stack *stack)
+{
+ if (!stack || !stack->tail)
+ return NULL;
+
+ return stack->tail->data;
+}
+
+void stack_clear(struct stack *stack)
+{
+ while (stack_pop(stack))
+ ;
+}
diff --git a/libs/libc/str.c b/libs/libc/str.c
new file mode 100644
index 0000000..ba16920
--- /dev/null
+++ b/libs/libc/str.c
@@ -0,0 +1,207 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <def.h>
+#include <errno.h>
+#include <mem.h>
+#include <str.h>
+
+u32 strlen(const char *s)
+{
+ const char *ss = s;
+ while (*ss)
+ ss++;
+ return ss - s;
+}
+
+char *strcpy(char *dst, const char *src)
+{
+ char *q = dst;
+ const char *p = src;
+ char ch;
+
+ do {
+ *q++ = ch = *p++;
+ } while (ch);
+
+ return dst;
+}
+
+char *strncpy(char *dst, const char *src, u32 n)
+{
+ char *q = dst;
+
+ while (n-- && (*dst++ = *src++))
+ ;
+
+ return q;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+ const u8 *c1 = (const u8 *)s1;
+ const u8 *c2 = (const u8 *)s2;
+ u8 ch;
+ int d = 0;
+
+ while (1) {
+ d = (int)(ch = *c1++) - (int)*c2++;
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
+
+int strncmp(const char *s1, const char *s2, u32 n)
+{
+ const u8 *c1 = (const u8 *)s1;
+ const u8 *c2 = (const u8 *)s2;
+ u8 ch;
+ int d = 0;
+
+ while (n--) {
+ d = (int)(ch = *c1++) - (int)*c2++;
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
+
+char *strchr(char *s, int c)
+{
+ while (*s != (char)c) {
+ if (!*s)
+ return NULL;
+ s++;
+ }
+
+ return s;
+}
+
+char *strrchr(char *s, int c)
+{
+ char *ret = 0;
+
+ do {
+ if (*s == c)
+ ret = s;
+ } while (*s++);
+
+ return ret;
+}
+
+char *strcat(char *dst, const char *src)
+{
+ strcpy(strchr(dst, '\0'), src);
+ return dst;
+}
+
+char *strncat(char *dst, const char *src, u32 n)
+{
+ strncpy(strchr(dst, '\0'), src, n);
+ return dst;
+}
+
+char *strinv(char *s)
+{
+ u32 s_str = strlen(s);
+
+ int iterations = (int)s_str / 2;
+ for (int i = 0; i < iterations; i++) {
+ char aux = s[i];
+ s[i] = s[(s_str - i) - 1];
+ s[(s_str - i) - 1] = aux;
+ }
+ return s;
+}
+
+char *strdup(const char *s)
+{
+ int l = strlen(s) + 1;
+ char *d = malloc(l);
+
+ memcpy(d, s, l);
+
+ return d;
+}
+
+const char *strerror(u32 error)
+{
+ switch (error) {
+ case 0:
+ return "Success";
+ case EPERM:
+ return "Operation not permitted";
+ case ENOENT:
+ return "No such file or directory";
+ case ESRCH:
+ return "No such process";
+ case EINTR:
+ return "Interrupted system call";
+ case EIO:
+ return "I/O error";
+ case ENXIO:
+ return "No such device or address";
+ case E2BIG:
+ return "Argument list too long";
+ case ENOEXEC:
+ return "Exec format error";
+ case EBADF:
+ return "Bad file number";
+ case ECHILD:
+ return "No child processes";
+ case EAGAIN:
+ return "Try again";
+ case ENOMEM:
+ return "Out of memory";
+ case EACCES:
+ return "Permission denied";
+ case EFAULT:
+ return "Bad address";
+ case ENOTBLK:
+ return "Block device required";
+ case EBUSY:
+ return "Device or resource busy";
+ case EEXIST:
+ return "File exists";
+ case EXDEV:
+ return "Cross-device link";
+ case ENODEV:
+ return "No such device";
+ case ENOTDIR:
+ return "Not a directory";
+ case EISDIR:
+ return "Is a directory";
+ case EINVAL:
+ return "Invalid argument";
+ case ENFILE:
+ return "File table overflow";
+ case EMFILE:
+ return "Too many open files";
+ case ENOTTY:
+ return "Not a typewriter";
+ case ETXTBSY:
+ return "Text file busy";
+ case EFBIG:
+ return "File too large";
+ case ENOSPC:
+ return "No space left on device";
+ case ESPIPE:
+ return "Illegal seek";
+ case EROFS:
+ return "Read-only file system";
+ case EMLINK:
+ return "Too many links";
+ case EPIPE:
+ return "Broken pipe";
+ case EDOM:
+ return "Math argument out of domain of func";
+ case ERANGE:
+ return "Math result not representable";
+ case EMAX:
+ return "Max errno";
+ default:
+ return "Unknown error";
+ }
+}
diff --git a/libs/libc/sys.c b/libs/libc/sys.c
new file mode 100644
index 0000000..491c37c
--- /dev/null
+++ b/libs/libc/sys.c
@@ -0,0 +1,203 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// Syscall implementation
+
+#include <arg.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys.h>
+
+#if defined(userspace)
+
+/**
+ * Definitions
+ */
+
+#define ERRIFY(ret) \
+ if (ret < 0) { \
+ errno = -ret; \
+ return -1; \
+ } \
+ errno = 0; \
+ return ret
+
+res sys0(enum sys num);
+res sys0(enum sys num)
+{
+ int a;
+ __asm__ volatile("int $0x80" : "=a"(a) : "0"(num));
+ ERRIFY(a);
+}
+
+res sys1(enum sys num, int d1);
+res sys1(enum sys num, int d1)
+{
+ int a;
+ __asm__ volatile("int $0x80" : "=a"(a) : "0"(num), "b"((int)d1));
+ ERRIFY(a);
+}
+
+res sys2(enum sys num, int d1, int d2);
+res sys2(enum sys num, int d1, int d2)
+{
+ int a;
+ __asm__ volatile("int $0x80" : "=a"(a) : "0"(num), "b"((int)d1), "c"((int)d2));
+ ERRIFY(a);
+}
+
+res sys3(enum sys num, int d1, int d2, int d3);
+res sys3(enum sys num, int d1, int d2, int d3)
+{
+ int a;
+ __asm__ volatile("int $0x80"
+ : "=a"(a)
+ : "0"(num), "b"((int)d1), "c"((int)d2), "d"((int)d3));
+ ERRIFY(a);
+}
+
+res sys4(enum sys num, int d1, int d2, int d3, int d4);
+res sys4(enum sys num, int d1, int d2, int d3, int d4)
+{
+ int a;
+ __asm__ volatile("int $0x80"
+ : "=a"(a)
+ : "0"(num), "b"((int)d1), "c"((int)d2), "d"((int)d3), "S"((int)d4));
+ ERRIFY(a);
+}
+
+res sys5(enum sys num, int d1, int d2, int d3, int d4, int d5);
+res sys5(enum sys num, int d1, int d2, int d3, int d4, int d5)
+{
+ int a;
+ __asm__ volatile("int $0x80"
+ : "=a"(a)
+ : "0"(num), "b"((int)d1), "c"((int)d2), "d"((int)d3), "S"((int)d4),
+ "D"((int)d5));
+ ERRIFY(a);
+}
+
+/**
+ * Syscalls
+ */
+
+res sys_alloc(u32 size, u32 *addr)
+{
+ u32 id = 0;
+ return sys4(SYS_ALLOC, (int)size, (int)addr, (int)&id, 0);
+}
+
+res sys_free(void *ptr)
+{
+ return sys1(SYS_FREE, (int)ptr);
+}
+
+res shalloc(u32 size, u32 *addr, u32 *id)
+{
+ return sys4(SYS_ALLOC, (int)size, (int)addr, (int)id, 1);
+}
+
+res shaccess(u32 id, u32 *addr, u32 *size)
+{
+ return sys3(SYS_SHACCESS, (int)id, (int)addr, (int)size);
+}
+
+void loop(void)
+{
+ sys0(SYS_LOOP);
+}
+
+res read(const char *path, void *buf, u32 offset, u32 count)
+{
+ return sys4(SYS_READ, (int)path, (int)buf, (int)offset, (int)count);
+}
+
+res write(const char *path, const void *buf, u32 offset, u32 count)
+{
+ return sys4(SYS_WRITE, (int)path, (int)buf, (int)offset, (int)count);
+}
+
+res ioctl(const char *path, ...)
+{
+ va_list ap;
+ int args[4] = { 0 };
+
+ va_start(ap, path);
+ for (int i = 0; i < 4; i++)
+ args[i] = va_arg(ap, int);
+ va_end(ap);
+
+ return sys5(SYS_IOCTL, (int)path, args[0], args[1], args[2], args[3]);
+}
+
+res stat(const char *path, struct stat *buf)
+{
+ return sys2(SYS_STAT, (int)path, (int)buf);
+}
+
+res poll(const char **files)
+{
+ return sys1(SYS_POLL, (int)files);
+}
+
+res exec(const char *path, ...)
+{
+ va_list ap;
+ int args[4] = { 0 };
+
+ va_start(ap, path);
+ for (int i = 0; i < 4; i++)
+ args[i] = va_arg(ap, int);
+ va_end(ap);
+
+ return sys5(SYS_EXEC, (int)path, args[0], args[1], args[2], args[3]);
+}
+
+res yield(void)
+{
+ return sys0(SYS_YIELD);
+}
+
+static void atexit_trigger(void);
+void exit(s32 status)
+{
+ atexit_trigger();
+ sys1(SYS_EXIT, (int)status);
+ while (1)
+ yield();
+}
+
+res boot(u32 cmd)
+{
+ return sys2(SYS_BOOT, SYS_BOOT_MAGIC, cmd);
+}
+
+u32 time(void)
+{
+ return (u32)sys0(SYS_TIME);
+}
+
+/**
+ * At exit
+ */
+
+#define ATEXIT_MAX 32
+
+static u32 slot = 0;
+static void (*funcs[ATEXIT_MAX])(void) = { 0 };
+
+static void atexit_trigger(void)
+{
+ while (slot-- > 0) {
+ if (funcs[slot]) {
+ funcs[slot]();
+ funcs[slot] = NULL;
+ }
+ }
+}
+
+void atexit(void (*func)(void))
+{
+ if (slot < ATEXIT_MAX)
+ funcs[slot++] = func;
+}
+
+#endif