diff options
Diffstat (limited to 'src/user/lib')
-rw-r--r-- | src/user/lib/Makefile | 12 | ||||
-rw-r--r-- | src/user/lib/include/mutex.h | 15 | ||||
-rw-r--r-- | src/user/lib/include/tce/mem.h | 9 | ||||
-rw-r--r-- | src/user/lib/include/tce/syscall.h | 21 | ||||
-rw-r--r-- | src/user/lib/start.c | 8 | ||||
-rw-r--r-- | src/user/lib/std/mutex.c | 22 | ||||
-rw-r--r-- | src/user/lib/std/stdio.c | 51 | ||||
-rw-r--r-- | src/user/lib/tce/mem.c | 262 | ||||
-rw-r--r-- | src/user/lib/tce/syscall.c | 68 |
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); +} |