BarryServer : Git

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

// Related

Nucleus

Barry Improved context switching and interrupt handling d46e09a (3 years, 2 months ago)
diff --git a/task/clone.c b/task/clone.c
index fe0ad88..93c0b94 100644
--- a/task/clone.c
+++ b/task/clone.c
@@ -62,9 +62,12 @@ clone(int flags)
 	child->pageDir = clone_dir();
 
 	/* Split tasks here */
-	child->eip = (uintptr_t) &&end;
+	asm volatile("mov %%esi, %0" : "=r" (child->esi));
+	asm volatile("mov %%edi, %0" : "=r" (child->edi));
+	asm volatile("mov %%ebx, %0" : "=r" (child->ebx));
 	asm volatile("mov %%esp, %0" : "=r" (child->esp));
 	asm volatile("mov %%ebp, %0" : "=r" (child->ebp));
+	child->eip = (uintptr_t) &&end;
 	add(readyQueue[child->priority], child);
 	tid = child->tid;
 	put(child);
diff --git a/task/scheduler.c b/task/scheduler.c
index 485301e..b35192c 100644
--- a/task/scheduler.c
+++ b/task/scheduler.c
@@ -11,6 +11,10 @@
 
 #define PRIORITY_COUNT 6
 
+void context_switch(uintptr_t eip, page_dir_t pagedir,
+                    uintptr_t esi, uintptr_t edi, uintptr_t ebx,
+                    uintptr_t ebp, uintptr_t esp);
+
 ObjectList *readyQueue[PRIORITY_COUNT];
 
 /* Switch to a task */
@@ -20,6 +24,9 @@ switch_to_task(Task *task)
 	/* Save current task state */
 	if (__builtin_expect(!!current, 1)) {
 		lock(current);
+		asm volatile("mov %%esi, %0" : "=r" (current->esi));
+		asm volatile("mov %%edi, %0" : "=r" (current->edi));
+		asm volatile("mov %%ebx, %0" : "=r" (current->ebx));
 		asm volatile("mov %%esp, %0" : "=r" (current->esp));
 		asm volatile("mov %%ebp, %0" : "=r" (current->ebp));
 		current->eip = (uintptr_t) &&end;
@@ -28,22 +35,9 @@ switch_to_task(Task *task)
 	}
 
 	/* Switch to new context */
-	uintptr_t eip, esp, ebp;
 	current = task; /* Given reference, so no get() */
-	eip = current->eip;
-	esp = current->esp;
-	ebp = current->ebp;
-	asm volatile (
-		"cli;"
-		"movl %0, %%ecx;"
-		"movl %1, %%esp;"
-		"movl %2, %%ebp;"
-		"movl %3, %%cr3;"
-		"sti;"
-		"jmp *%%ecx"
-		:: "g" (eip), "g" (esp),
-		   "g" (ebp), "g" (current->pageDir)
-	);
+	context_switch(current->eip, current->pageDir, current->esi,
+	               current->edi, current->ebx, current->ebp, current->esp);
 end:
 	/* This prevents GCC from optimising the jump to be after the return */
 	asm volatile("":::"memory");
diff --git a/task/switch.S b/task/switch.S
new file mode 100644
index 0000000..5ef5437
--- /dev/null
+++ b/task/switch.S
@@ -0,0 +1,21 @@
+/*
+ * This file contains the context switch routine.  This routine will switch the
+ * current context, but will not save any state, so it should only be called by
+ * the scheduler.  Since the stack and page directory will get switched, care
+ * must be taken to read and set the registers in the correct order.
+ */
+
+/* Perform a context switch */
+.globl context_switch
+context_switch:
+	cli
+	mov 4(%esp), %ecx
+	mov 8(%esp), %eax
+	mov 12(%esp), %esi
+	mov 16(%esp), %edi
+	mov 20(%esp), %ebx
+	mov 24(%esp), %ebp
+	mov 28(%esp), %esp
+	mov %eax, %cr3
+	sti
+	jmp *%ecx
diff --git a/task/syscall.c b/task/syscall.c
index e0b2d23..8e33ef4 100644
--- a/task/syscall.c
+++ b/task/syscall.c
@@ -87,9 +87,11 @@ struct SyscallEntry syscalls[] = {
 };
 
 /* Handle a syscall */
-int
-syscall_handler(int num, uintptr_t args)
+void
+syscall_handler(struct InterruptFrame *frame)
 {
+	int num = frame->eax;
+	uintptr_t args = frame->esi;
 	int ret = -EINVAL;
 	enter_syscall_context(num);
 
@@ -115,5 +117,5 @@ syscall_handler(int num, uintptr_t args)
 
 end:
 	exit_syscall_context();
-	return ret;
+	frame->eax = ret;
 }
diff --git a/task/task.c b/task/task.c
index 597df30..69af014 100644
--- a/task/task.c
+++ b/task/task.c
@@ -14,6 +14,7 @@
 
 void init_scheduler(void);
 void timer_handler(struct InterruptFrame *frame);
+void syscall_handler(struct InterruptFrame *frame);
 
 static void task_new(Object *);
 static void task_delete(Object *);
@@ -110,7 +111,7 @@ init_tasking(void)
 
 	init_scheduler();
 	register_interrupt(0, timer_handler);
-
+	register_exception(128, syscall_handler);
 }
 
 /* Get the current task's PID */