Nucleus
Barry Multitasking support db9a0c1 (3 years, 3 months ago)
diff --git a/task/task.c b/task/task.c
new file mode 100644
index 0000000..507caae
--- /dev/null
+++ b/task/task.c
@@ -0,0 +1,88 @@
+/*
+ * This file is in control of initialising the tasking subsystem. It also
+ * implements the Task object.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <nucleus/cpu.h>
+#include <nucleus/task.h>
+#include <nucleus/memory.h>
+#include <nucleus/object.h>
+
+void timer_handler(struct InterruptFrame *frame);
+
+static void *task_new(void);
+static void task_delete(Object *);
+
+/* Task object type */
+ObjectType taskType = {
+ .new = task_new,
+ .delete = task_delete,
+};
+
+Task *currentTask[MAX_CPUS];
+pid_t nextTid = 1;
+
+/* Create a new Task */
+static void *
+task_new(void)
+{
+ Task *task = kmalloc(sizeof(Task));
+ task->tid = nextTid++;
+ task->priority = NORMAL;
+ task->state = READY;
+ return task;
+}
+
+/* Destroy a Task */
+static void
+task_delete(Object *obj)
+{
+ kfree(obj);
+}
+
+extern char stackTop[];
+
+/* Move the stack */
+static void
+move_stack(uintptr_t top, size_t size)
+{
+ size_t offset;
+ uintptr_t oldStack, oldBase;
+ uintptr_t newStack, newBase;
+ top -= sizeof(uintptr_t);
+ asm volatile("mov %%esp, %0" : "=r" (oldStack));
+ asm volatile("mov %%ebp, %0" : "=r" (oldBase));
+ offset = top - (uintptr_t) stackTop;
+ newStack = oldStack + offset;
+ newBase = oldBase + offset;
+
+ memcpy((void *) newStack, (void *) oldStack, (size_t) stackTop - oldStack);
+
+ /* Update pointers on the stack */
+ uintptr_t i, tmp;
+ for (i = top; i > top - size; i -= sizeof(uintptr_t)) {
+ tmp = *(uintptr_t *) i;
+ if (tmp > oldStack && tmp < (uintptr_t) stackTop) {
+ tmp += offset;
+ *(uintptr_t *) i = tmp;
+ }
+ }
+
+ asm volatile("mov %0, %%esp" :: "r" (newStack));
+ asm volatile("mov %0, %%ebp" :: "r" (newBase));
+}
+
+/* Initialise tasking */
+void
+init_tasking(void)
+{
+ move_stack(0xF0800000, 0x2000);
+
+ current = new(&taskType);
+ asm volatile("mov %%cr3, %0" : "=r" (current->pageDir));
+
+ register_interrupt(0, timer_handler);
+}