Begin multitasking refactor to support ring-3 TSS
diff --git a/src/kernel/task.c b/src/kernel/task.c
index 116e4a2..d538e01 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -11,7 +11,7 @@
 
 bool tasks_initialized = false;
 
-void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip);
+void _init_tasks(struct registers *regs);
 
 void init_tasks()
 {
@@ -22,10 +22,10 @@
 
 void _sys_init_tasks_h(struct registers *regs)
 {
-	_init_tasks(regs->esp, regs->ebp, regs->eip);
+	_init_tasks(regs);
 }
 
-void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip)
+void _init_tasks(struct registers *regs)
 {
 	processes[0] = (struct process){
 		.exists = true,
@@ -33,12 +33,13 @@
 		.ring = 0,
 		.uid = 0,
 		.page_directory_p = VIRT_TO_PHYS(kernel_page_directory),
-		// Obviously this isn't the actual stack position, but we want it to
-		// grow down from 4 gb so we will pretend that the first task has its
-		// stack at exactly 4gb and work from there. Because the new stack will
-		// be mapped to any random frame, it doesn't actually matter where we
-		// put it, we just want somewhere that won't collide with any user space
-		// stuff or our heap.
+		// Obviously this isn't the actual stack position, but we want
+		// it to grow down from 4 gb so we will pretend that the first
+		// task has its stack at exactly 4gb and work from
+		// there. Because the new stack will be mapped to any random
+		// frame, it doesn't actually matter where we put it, we just
+		// want somewhere that won't collide with any user space stuff
+		// or our heap.
 		.last_stack_pos = 0xFFFFF000,
 	};
 	strcpy(processes[0].name, "kernel");
@@ -47,11 +48,10 @@
 
 	first_task->next = NULL;
 	first_task->prev = NULL;
+	memset(&first_task->task, 0, sizeof(struct task));
 	first_task->task = (struct task){
 		.proc = &processes[0],
-		.esp = kernel_esp,
-		.ebp = kernel_ebp,
-		.eip = kernel_eip,
+		.state = *regs,
 		.id = next_task_id++,
 		.waiting = false,
 	};
@@ -101,11 +101,15 @@
 	struct ll_task_i *ll_task = malloc(sizeof(struct ll_task_i));
 	memset(ll_task, 0, sizeof(struct ll_task_i));
 	struct task *task = &ll_task->task;
+	// New task is basically the same as the old one but with just a
+	// few changes
+	*task = current_task->task;
 
-	task->proc = proc;
+	// Namely a new TID
 	task->id = next_task_id++;
-	task->ebp = task->esp = new_stack_base_v;
-	task->eip = (uint)function;
+	// And stack, frame, and instruction pointers
+	task->state.ebp = task->state.esp = new_stack_base_v;
+	task->state.eip = (uint)function;
 	task->waiting = false;
 
 	last_task->next = ll_task;
@@ -132,8 +136,9 @@
 
 	if (current_task->next != NULL)
 	{
-		// If this is NULL, task will be first_task, which can't be the current task
-		// because we know there are more than one task, and this is the last one.
+		// If this is NULL, task will be first_task, which can't be
+		// the current task because we know there are more than one
+		// task, and this is the last one.
 		current_task->next->prev = current_task->prev;
 		task = current_task->next;
 	}
@@ -152,27 +157,29 @@
 	asm("sti");
 }
 
-extern void _switch_to_task(uint page_directory, uint eip, uint ebp, uint esp);
+extern void _switch_to_task(uint page_directory, struct registers ctx);
+#if 0
+{
+	asm("mov %0, %%ecx" :: "g"(page_directory));
+	asm("mov %ecx, %cr3");
+	// "ctx" will be at the top of the stack.
+	asm("iret");
+}
+#endif
 
 void switch_to_task(struct task *task)
 {
-	_switch_to_task(task->proc->page_directory_p, task->eip, task->ebp,
-					task->esp);
+	_switch_to_task(task->proc->page_directory_p, task->state);
 	__builtin_unreachable();
 }
 
-// WARNING: do not call this manually, it will clobber everything
-// except esp, ebp, and eip (obviously). Use switch_task in task_api.s
-// instead.
-void _do_switch_task(uint eip, uint ebp, uint esp)
+void _do_switch_task(struct registers regs)
 {
 	// sti is called in switch_to_task
 	asm("cli");
 
 	// save context for this task
-	current_task->task.ebp = ebp;
-	current_task->task.esp = esp;
-	current_task->task.eip = eip;
+	current_task->task.state = regs;
 
 	struct ll_task_i *original = current_task;
 
@@ -213,3 +220,9 @@
 
 	asm("sti");
 }
+
+void switch_task(struct registers ctx)
+{
+	if (tasks_initialized)
+		_do_switch_task(ctx);
+}