BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / db9a0c170420002cff8cade7e3e598ac9d6fb25a

// Related

Nucleus

Barry Multitasking support db9a0c1 (3 years, 3 months ago)
diff --git a/include/nucleus/task.h b/include/nucleus/task.h
new file mode 100644
index 0000000..2761a3f
--- /dev/null
+++ b/include/nucleus/task.h
@@ -0,0 +1,50 @@
+#ifndef _NUCLEUS_TASK_H
+#define _NUCLEUS_TASK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <nucleus/cpu.h>
+#include <nucleus/object.h>
+#include <nucleus/memory.h>
+
+typedef struct Task Task;
+
+/* Task priorities */
+enum Priority {
+	NONE,
+	LOWEST,
+	LOW,
+	NORMAL,
+	HIGH,
+	HIGHEST,
+};
+
+/* Task states */
+enum State {
+	RUNNING,
+	READY,
+	TERMINATED,
+};
+
+/* Structure for a Task */
+struct Task {
+	Object obj;
+	pid_t tid;
+	enum Priority priority;
+	enum State state;
+
+	uintptr_t esp, ebp, eip;
+	page_dir_t pageDir;
+	Task *next;
+};
+
+extern ObjectType taskType;
+
+extern Task *currentTask[];
+#define current currentTask[CPUID]
+
+void init_tasking(void);
+void schedule(void);
+pid_t clone(int flags);
+
+#endif
diff --git a/kernel/panic.c b/kernel/panic.c
index 3e0ac4f..5d1a847 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -256,7 +256,6 @@ kprintf(char *fmt, ...)
 	outb(0xE9, '6');
 	outb(0xE9, 'm');
 
-
 	char buf[1024], *p = buf;
 
 	/* Print message to serial port */
@@ -279,7 +278,6 @@ panic(char *fmt, ...)
 	outb(0xE9, '1');
 	outb(0xE9, 'm');
 
-
 	char buf[1024], *p = buf;
 
 	/* Print error to serial port */
@@ -291,7 +289,7 @@ panic(char *fmt, ...)
 		outb(0xE9, *p++);
 	outb(0xE9, '\n');
 
-	asm volatile("cli");
+	asm volatile("sti");
 	while (1)
 		asm volatile("hlt");
 }
diff --git a/object/manager.c b/object/manager.c
index a0b0c8b..301b6ca 100644
--- a/object/manager.c
+++ b/object/manager.c
@@ -6,7 +6,7 @@
  * controls their instantiation and deletion.
  */
 
-#include "object.h"
+#include <nucleus/object.h>
 
 /* Obtain a reference to an object */
 void *
diff --git a/task/clone.c b/task/clone.c
new file mode 100644
index 0000000..0c95083
--- /dev/null
+++ b/task/clone.c
@@ -0,0 +1,41 @@
+/*
+ * This file contains the clone() function/system call.  It creates a new task,
+ * and copies most of the attributes from the parent task into it.
+ */
+
+#include <sys/types.h>
+#include <nucleus/task.h>
+
+/* Read the EIP */
+static uintptr_t
+read_eip(void)
+{
+	uintptr_t eip;
+	asm volatile("movl 4(%%ebp), %0" : "=r" (eip));
+	return eip;
+}
+
+/* Clone a task */
+pid_t
+clone(int flags)
+{
+	Task *parent = current, *child = new(&taskType), *tmp;
+
+	child->pageDir = clone_dir();
+
+	parent->next = child;
+	child->next = parent;
+
+	/* Split tasks here */
+	uintptr_t esp, ebp, eip;
+	eip = read_eip();
+	if (current == parent) {
+		asm volatile("mov %%esp, %0" : "=r" (esp));
+		asm volatile("mov %%ebp, %0" : "=r" (ebp));
+		child->esp = esp;
+		child->ebp = ebp;
+		child->eip = eip;
+		return child->tid;
+	}
+	return 0;
+}
diff --git a/task/scheduler.c b/task/scheduler.c
new file mode 100644
index 0000000..9ad1405
--- /dev/null
+++ b/task/scheduler.c
@@ -0,0 +1,61 @@
+/*
+ * This file contains the scheduler.  It implements a basic task switching
+ * routine, as well as the schedule() function.  The scheduler can be called
+ * from anywhere, and will switch to the next task decided by the scheduler
+ * rules.  If it cannot find a task to schedule, it just idles until one becomes
+ * available.  This avoids the need for an idle task.
+ */
+
+#include <nucleus/panic.h>
+#include <nucleus/task.h>
+
+/* Read the EIP */
+static uintptr_t
+read_eip(void)
+{
+	uintptr_t eip;
+	asm volatile("movl 4(%%ebp), %0" : "=r" (eip));
+	return eip;
+}
+
+/* Switch to a task */
+static void
+switch_to_task(Task *task)
+{
+	uintptr_t esp, ebp, eip;
+	asm volatile("mov %%esp, %0" : "=r" (esp));
+	asm volatile("mov %%ebp, %0" : "=r" (ebp));
+	eip = read_eip();
+	if (eip == 0x10032004) /* Magic number */
+		return;
+
+	current->esp = esp;
+	current->ebp = ebp;
+	current->eip = eip;
+	current = task;
+	esp = current->esp;
+	ebp = current->ebp;
+	eip = current->eip;
+
+	asm volatile (
+		"cli;"
+		"movl %0, %%ecx;"
+		"movl %1, %%esp;"
+		"movl %2, %%ebp;"
+		"movl %3, %%cr3;"
+		"movl $0x10032004, %%eax;"
+		"sti;"
+		"jmp *%%ecx"
+		:: "g" (eip), "g" (esp), "g" (ebp), "g" (current->pageDir)
+	);
+}
+
+/* Schedule the next task */
+void
+schedule(void)
+{
+	Task *task = current;
+	if (!task->next)
+		return;
+	switch_to_task(task->next);
+}
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);
+}
diff --git a/task/time.c b/task/time.c
new file mode 100644
index 0000000..39675e4
--- /dev/null
+++ b/task/time.c
@@ -0,0 +1,30 @@
+/*
+ * This file controls the system clock and contains the functions related to
+ * getting and setting the time from various sources.  It keeps a monotonic
+ * clock internally, but can also make use of the tasks' clocks, and the RTC.
+ */
+
+#include <stdint.h>
+#include <nucleus/cpu.h>
+#include <nucleus/task.h>
+
+uint32_t monotonic = 0;
+uint8_t slice[MAX_CPUS] = {0};
+
+/* Timer interrupt */
+void
+timer_handler(struct InterruptFrame *frame)
+{
+	monotonic++;
+
+	/* Account timeslices */
+	slice[CPUID]++;
+	if (!current)
+		return;
+
+	/* Call scheduler */
+	if (slice[CPUID] < current->priority)
+		return;
+	slice[CPUID] = 0;
+	schedule();
+}