summaryrefslogtreecommitdiff
path: root/src/user/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/lib')
-rw-r--r--src/user/lib/Makefile12
-rw-r--r--src/user/lib/include/mutex.h15
-rw-r--r--src/user/lib/include/tce/mem.h9
-rw-r--r--src/user/lib/include/tce/syscall.h21
-rw-r--r--src/user/lib/start.c8
-rw-r--r--src/user/lib/std/mutex.c22
-rw-r--r--src/user/lib/std/stdio.c51
-rw-r--r--src/user/lib/tce/mem.c262
-rw-r--r--src/user/lib/tce/syscall.c68
9 files changed, 468 insertions, 0 deletions
diff --git a/src/user/lib/Makefile b/src/user/lib/Makefile
new file mode 100644
index 0000000..a4d68e7
--- /dev/null
+++ b/src/user/lib/Makefile
@@ -0,0 +1,12 @@
+Out = _user.o
+Obj = tce/syscall.o tce/mem.o \
+ std/mutex.o std/stdio.o \
+ start.o
+ExtObj = $(SrcPath)/common/_common.o
+
+include $(SrcPath)/common.make
+
+CFLAGS = -I$(SrcPath)/common/include -I$(SrcPath)/user/lib/include
+
+LDFLAGS += -r
+
diff --git a/src/user/lib/include/mutex.h b/src/user/lib/include/mutex.h
new file mode 100644
index 0000000..a6b949b
--- /dev/null
+++ b/src/user/lib/include/mutex.h
@@ -0,0 +1,15 @@
+#ifndef DEF_MUTEX_H
+#define DEF_MUTEX_H
+
+#include <tce/syscall.h>
+
+#define MUTEX_LOCKED 1
+#define MUTEX_UNLOCKED 0
+
+//A mutex is just an uint32_t
+
+void mutex_lock(uint32_t* mutex); //wait for mutex to be free
+int mutex_lockE(uint32_t* mutex); //lock mutex only if free, returns !0 if locked, 0 if was busy
+void mutex_unlock(uint32_t* mutex);
+
+#endif
diff --git a/src/user/lib/include/tce/mem.h b/src/user/lib/include/tce/mem.h
new file mode 100644
index 0000000..ab17bde
--- /dev/null
+++ b/src/user/lib/include/tce/mem.h
@@ -0,0 +1,9 @@
+#ifndef DEF_HEAP_H
+#define DEF_HEAP_H
+
+#include <tce/syscall.h>
+
+void* malloc(size_t size);
+void free(void* p);
+
+#endif
diff --git a/src/user/lib/include/tce/syscall.h b/src/user/lib/include/tce/syscall.h
new file mode 100644
index 0000000..5257a02
--- /dev/null
+++ b/src/user/lib/include/tce/syscall.h
@@ -0,0 +1,21 @@
+#ifndef DEF_SYSCALL_H
+#define DEF_SYSCALL_H
+
+#include <types.h>
+
+#define NEW_STACK_SIZE 0x8000
+
+void thread_exit();
+void schedule();
+void thread_sleep(int time);
+void process_exit(int retval);
+void printk(char* str);
+void thread_new(void (*entry)(void*), void *data);
+void irq_wait(int number);
+int proc_priv();
+
+int proc_setheap(size_t start, size_t end);
+int shm_create(size_t offset, size_t length);
+int shm_delete(size_t offset);
+
+#endif
diff --git a/src/user/lib/start.c b/src/user/lib/start.c
new file mode 100644
index 0000000..3dbb994
--- /dev/null
+++ b/src/user/lib/start.c
@@ -0,0 +1,8 @@
+#include <tce/syscall.h>
+
+extern int main();
+
+void start() {
+ int ret = main();
+ process_exit(ret);
+}
diff --git a/src/user/lib/std/mutex.c b/src/user/lib/std/mutex.c
new file mode 100644
index 0000000..ac0ee8f
--- /dev/null
+++ b/src/user/lib/std/mutex.c
@@ -0,0 +1,22 @@
+#include <mutex.h>
+
+static uint32_t atomic_exchange(uint32_t* ptr, uint32_t newval) {
+ uint32_t r;
+ asm volatile("xchg (%%ecx), %%eax" : "=a"(r) : "c"(ptr), "a"(newval));
+ return r;
+}
+
+void mutex_lock(uint32_t* mutex) {
+ while (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) {
+ thread_sleep(1);
+ }
+}
+
+int mutex_lockE(uint32_t* mutex) {
+ if (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) return 0;
+ return 1;
+}
+
+void mutex_unlock(uint32_t* mutex) {
+ *mutex = MUTEX_UNLOCKED;
+}
diff --git a/src/user/lib/std/stdio.c b/src/user/lib/std/stdio.c
new file mode 100644
index 0000000..3b24da1
--- /dev/null
+++ b/src/user/lib/std/stdio.c
@@ -0,0 +1,51 @@
+#include <stdlib.h>
+
+void printk_int(int number) {
+ if (number == 0) {
+ printk("0");
+ return;
+ }
+ int negative = 0;
+ if (number < 0) {
+ negative = 1;
+ number = 0 - number;
+ }
+ int order = 0, temp = number, i;
+ char numbers[] = "0123456789";
+ while (temp > 0) {
+ order++;
+ temp /= 10;
+ }
+
+ char *s, *r;
+ s = malloc(order + (negative ? 2 : 1));
+ if (negative) {
+ s[0] = '-';
+ r = s + 1;
+ } else {
+ r = s;
+ }
+
+ for (i = order; i > 0; i--) {
+ r[i - 1] = numbers[number % 10];
+ number /= 10;
+ }
+ r[order] = 0;
+ printk(s);
+ free(s);
+}
+
+void printk_hex(unsigned v) {
+ char s[11] = {'0', 'x', 0};
+
+ int i;
+
+ char hexdigits[] = "0123456789ABCDEF";
+
+ for (i = 0; i < 8; i++) {
+ s[i + 2] = (hexdigits[v >> 28]);
+ v = v << 4;
+ }
+ s[11] = 0;
+ printk(s);
+}
diff --git a/src/user/lib/tce/mem.c b/src/user/lib/tce/mem.c
new file mode 100644
index 0000000..e30e36b
--- /dev/null
+++ b/src/user/lib/tce/mem.c
@@ -0,0 +1,262 @@
+#include <tce/mem.h>
+
+struct heap_header {
+ uint32_t magic;
+ uint32_t is_hole;
+ size_t size;
+};
+
+struct heap_footer {
+ uint32_t magic;
+ struct heap_header *header;
+};
+
+struct heap {
+ struct heap_header **idx;
+ uint32_t idxused;
+ size_t start_addr, end_addr, max_end;
+};
+
+int heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize);
+void* heap_alloc(struct heap *heap, size_t sz);
+void heap_free(struct heap *heap, void* ptr);
+
+#define HEAP_MAGIC 0xBAD0BEEF
+#define HEAP_MIN_SIZE 0x4000
+
+/* ******************* GENERAL MEMORY FUNCTIONS ******************** */
+
+static struct heap h;
+static int heap_ok = 0;
+
+void* malloc(size_t size) {
+ if (heap_ok == 0) {
+ if (heap_create(&h, 0x20000000, 0x00010000, 0x00100000, 0x4F000000)) return 0;
+ heap_ok = 1;
+ }
+ return heap_alloc(&h, size);
+}
+
+void free(void* p) {
+ if (heap_ok == 0 || (size_t)p < h.start_addr || (size_t)p > h.end_addr) return;
+ heap_free(&h, p);
+}
+
+static int setheapseg (struct heap *heap, size_t start, size_t end, size_t prev_end) { //returns nonzero on error
+ if (heap == &h) {
+ return proc_setheap(start, end);
+ } //otherwise, something else might be done.
+ return -1;
+}
+
+/* ******************* HEAP HEADER ****************** */
+
+static void heapIdx_insert(struct heap *heap, struct heap_header *e) {
+ if ((heap->idxused + sizeof(struct heap_header*) + (size_t)heap->idx) >= heap->start_addr) return;
+
+ uint32_t iterator = 0, pos;
+ while (iterator < heap->idxused && heap->idx[iterator]->size < e->size) {
+ if (heap->idx[iterator] == e) return;
+ iterator++;
+ }
+ if (iterator == heap->idxused) {
+ heap->idx[heap->idxused++] = e;
+ } else {
+ pos = iterator;
+ iterator = heap->idxused;
+ while (iterator > pos) {
+ heap->idx[iterator] = heap->idx[iterator - 1];
+ iterator--;
+ }
+ heap->idxused++;
+ heap->idx[pos] = e;
+ }
+}
+
+static void heapIdx_remove(struct heap *heap, struct heap_header *e) {
+ uint32_t iterator;
+ for (iterator = 0; iterator < heap->idxused; iterator++) {
+ if (heap->idx[iterator] == e) break;
+ }
+ if (iterator == heap->idxused) return;
+ heap->idxused--;
+ while (iterator < heap->idxused) {
+ heap->idx[iterator] = heap->idx[iterator + 1];
+ iterator++;
+ }
+}
+
+/* ******************** HEAP CONTENTS ********************* */
+
+int heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize) {
+ if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000;
+
+ heap->start_addr = start + idxsize;
+ heap->end_addr = start + idxsize + datasize;
+ heap->max_end = start + idxsize + maxdatasize;
+
+ if (setheapseg(heap, start, heap->end_addr, 0)) return -1;
+
+ heap->idx = (struct heap_header**)start;
+ heap->idxused = 0;
+
+ struct heap_header *hole = (struct heap_header*) heap->start_addr;
+ hole->size = (heap->end_addr - heap->start_addr);
+ hole->magic = HEAP_MAGIC;
+ hole->is_hole = 1;
+
+ struct heap_footer *hole_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ hole_footer->header = hole;
+ hole_footer->magic = HEAP_MAGIC;
+
+ heapIdx_insert(heap, hole);
+ return 0;
+}
+
+static uint32_t heap_expand(struct heap *heap, size_t quantity) {
+ if (quantity & 0x0FFF) {
+ quantity = (quantity & 0xFFFFF000) + 0x1000;
+ }
+
+ if (heap->end_addr + quantity > heap->max_end) return 0;
+
+ size_t newEnd = heap->end_addr + quantity;
+
+ if (setheapseg(heap, (size_t)heap->idx, newEnd, heap->end_addr)) return 0; //failed to bigger segment
+
+ struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ struct heap_header *last_header = last_footer->header;
+ if (last_header->is_hole) {
+ heapIdx_remove(heap, last_header);
+ last_header->size += quantity;
+
+ last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer));
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+
+ heapIdx_insert(heap, last_header);
+ } else {
+ last_header = (struct heap_header*)heap->end_addr;
+ last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer));
+
+ last_header->is_hole = 1;
+ last_header->magic = HEAP_MAGIC;
+ last_header->size = quantity;
+
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+
+ heapIdx_insert(heap, last_header);
+ }
+
+ heap->end_addr = newEnd;
+
+ return 1;
+}
+
+static void heap_contract(struct heap *heap) {
+ struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ struct heap_header *last_header = last_footer->header;
+
+ if (last_header->is_hole == 0) return;
+
+ size_t quantity = 0;
+ while ((heap->end_addr - heap->start_addr) - quantity > HEAP_MIN_SIZE &&
+ (last_header->size - quantity) > 0x1000)
+ quantity += 0x1000;
+ if (quantity == 0) return;
+
+ size_t newEnd = heap->end_addr - quantity;
+
+ if (setheapseg(heap, (size_t)heap->idx, newEnd, heap->end_addr)) return; //error ocurred
+
+ heapIdx_remove(heap, last_header);
+ last_header->size -= quantity;
+ last_footer = (struct heap_footer*)((size_t)last_footer - quantity);
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+ heapIdx_insert(heap, last_header);
+
+ heap->end_addr = newEnd;
+}
+
+void* heap_alloc(struct heap *heap, size_t sz) {
+ size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer);
+ uint32_t iterator = 0;
+
+ while (iterator < heap->idxused) {
+ if (heap->idx[iterator]->size >= newsize) break;
+ iterator++;
+ }
+
+ if (iterator == heap->idxused) { //No hole is big enough
+ if (heap_expand(heap, (sz & 0xFFFFF000) + 0x1000) == 0) return 0; //FAILED
+ return heap_alloc(heap, sz);
+ }
+
+ struct heap_header *loc = heap->idx[iterator];
+ struct heap_footer *footer = (struct heap_footer*)((size_t)loc + loc->size - sizeof(struct heap_footer));
+ loc->is_hole = 0;
+ heapIdx_remove(heap, loc);
+
+ //If we have enough space to create a USEFUL new hole next to the allocated block, do it.
+ //If we do not, we might return a block that is a few bytes bigger than neede.
+ if (loc->size > (newsize + sizeof(struct heap_header) + sizeof(struct heap_footer))) {
+ loc->size = newsize;
+
+ //Write footer for block we return
+ struct heap_footer *newfooter = (struct heap_footer*)((size_t)loc + newsize - sizeof(struct heap_footer));
+ newfooter->header = loc;
+ newfooter->magic = HEAP_MAGIC;
+
+ //Write header for new hole we create
+ struct heap_header *nextloc = (struct heap_header*)((size_t)loc + newsize);
+ nextloc->is_hole = 1;
+ nextloc->magic = HEAP_MAGIC;
+ nextloc->size = ((size_t)footer - (size_t)nextloc + sizeof(struct heap_footer));
+ footer->header = nextloc; //Update footer
+ footer->magic = HEAP_MAGIC;
+
+ heapIdx_insert(heap, nextloc);
+ }
+
+ return (void*)((size_t)loc + sizeof(struct heap_header));
+}
+
+void heap_free(struct heap *heap, void* ptr) {
+ if (ptr == 0) return;
+ if ((size_t)ptr < heap->start_addr || (size_t)ptr > heap->end_addr) return;
+
+ struct heap_header *header = (struct heap_header*)((size_t)ptr - sizeof(struct heap_header));
+ struct heap_footer *footer = (struct heap_footer*)((size_t)header + header->size - sizeof(struct heap_footer));
+ if (header->magic != HEAP_MAGIC || footer->magic != HEAP_MAGIC) return;
+
+ //Unify left
+ struct heap_footer *prev_footer = (struct heap_footer*)((size_t)header - sizeof(struct heap_footer));
+ if (prev_footer->magic == HEAP_MAGIC && prev_footer->header->is_hole) {
+ header = prev_footer->header;
+ heapIdx_remove(heap, header);
+
+ footer->header = header;
+ header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer));
+ }
+
+ //Unify right
+ struct heap_header *next_header = (struct heap_header*)((size_t)footer + sizeof(struct heap_footer));
+ if (next_header->magic == HEAP_MAGIC && next_header->is_hole) {
+ heapIdx_remove(heap, next_header);
+ footer = (struct heap_footer*)((size_t)footer + next_header->size);
+
+ footer->header = header;
+ header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer));
+ }
+
+ header->is_hole = 1;
+
+ heapIdx_insert(heap, header);
+
+ if ((size_t)footer == (heap->end_addr - sizeof(struct heap_footer)) &&
+ header->size >= 0x2000 && (heap->end_addr - heap->start_addr > HEAP_MIN_SIZE)) {
+ heap_contract(heap);
+ }
+}
diff --git a/src/user/lib/tce/syscall.c b/src/user/lib/tce/syscall.c
new file mode 100644
index 0000000..ae58e73
--- /dev/null
+++ b/src/user/lib/tce/syscall.c
@@ -0,0 +1,68 @@
+#include <tce/syscall.h>
+#include <tce/mem.h>
+
+static int call(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f) {
+ unsigned ret;
+ asm volatile("int $64" : "=a"(ret) : "a"(a), "b"(b), "c"(c), "d"(d), "S"(e), "D"(f));
+ return ret;
+}
+
+void thread_exit() {
+ call(0, 0, 0, 0, 0, 0);
+}
+
+void schedule() {
+ call(1, 0, 0,0, 0, 0);
+}
+
+void thread_sleep(int time) {
+ call(2, time, 0, 0, 0, 0);
+}
+
+void process_exit(int retval) {
+ call(3, retval, 0, 0, 0, 0);
+}
+
+void printk(char* str) {
+ call(4, (unsigned)str, 0, 0, 0, 0);
+}
+
+//THREAD CREATION
+struct thread_start_data {
+ void (*entry)(void*);
+ void *data;
+ void *stack;
+};
+void thread_start(void *data) {
+ struct thread_start_data *tsd = data;
+ tsd->entry(tsd->data);
+ free(tsd->stack);
+ thread_exit();
+}
+void thread_new(void (*entry)(void*), void *data) {
+ struct thread_start_data *tsd = malloc(sizeof(struct thread_start_data));
+ tsd->entry = entry;
+ tsd->data = data;
+ tsd->stack = malloc(NEW_STACK_SIZE);
+ call(5, (unsigned)thread_start, (unsigned)tsd, (unsigned)(tsd->stack + NEW_STACK_SIZE), 0, 0);
+}
+
+void irq_wait(int number) {
+ call(6, number, 0, 0, 0, 0);
+}
+
+int proc_priv() {
+ return call(7, 0, 0, 0, 0, 0);
+}
+
+int proc_setheap(size_t start, size_t end) {
+ return call(8, start, end, 0, 0, 0);
+}
+
+int shm_create(size_t offset, size_t length) {
+ return call(9, offset, length, 0, 0, 0);
+}
+
+int shm_delete(size_t offset) {
+ return call(10, offset, 0, 0, 0, 0);
+}