Add threading, paging broken
diff --git a/src/kernel/.gdbinit b/src/kernel/.gdbinit
index 24efe1e..54e4e4c 100644
--- a/src/kernel/.gdbinit
+++ b/src/kernel/.gdbinit
@@ -1 +1,2 @@
+file kernel.elf
 target remote localhost:1234
diff --git a/src/kernel/Jmk b/src/kernel/Jmk
index 5774274..c299cf1 100644
--- a/src/kernel/Jmk
+++ b/src/kernel/Jmk
@@ -36,14 +36,18 @@
 			multiboot.o \
 			vfs_initrd.o \
 			syscall.o \
-			task.o
+			task.o \
+			task_api.o
 
 type(custom_link)
 
+debug-wait: kernel.elf
+	qemu-system-i386 -s -S -kernel kernel.elf
+
 debug: kernel.elf
 	qemu-system-i386 -s -S -kernel kernel.elf &
 	@echo run "target remote localhost:1234" to connect to qemu
-	gdb
+	gdb $<
 	@pkill qemu-system-i38
 
 qemu: kernel.elf
diff --git a/src/kernel/io.c b/src/kernel/io.c
index baa050f..0b300b5 100644
--- a/src/kernel/io.c
+++ b/src/kernel/io.c
@@ -55,8 +55,8 @@
 
 uint strlen(char *a)
 {
-	int i = 0;
-	for (; *a; i++)
+	uint i = 0;
+	for (; a[i]; i++)
 	{
 	}
 
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 22d4a35..ea5200b 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -2,13 +2,30 @@
 #include "descriptor_tables.h"
 #include "io.h"
 #include "log.h"
+#include "multiboot.h"
 #include "paging.h"
+#include "syscall.h"
+#include "task.h"
 #include "timer.h"
-#include "vga.h"
 #include "vfs.h"
 #include "vfs_initrd.h"
-#include "multiboot.h"
-#include "syscall.h"
+#include "vga.h"
+
+void greet()
+{
+	kprintf("Hello from get_task_id() = %d, get_process_id() = %d\n",
+			get_task_id(), get_process_id());
+}
+
+void other_thread()
+{
+	greet();
+	kprintf("Other thread returning...\n");
+	switch_task();
+
+	while (true)
+		asm volatile("hlt");
+}
 
 int kmain(struct multiboot_info *mboot)
 {
@@ -56,6 +73,16 @@
 	}
 #endif
 
+	kprintf("initializing tasks\n");
+	init_tasks();
+	kprintf("\ndone initializing tasks\n");
+
+	greet();
+	spawn_thread(other_thread);
+	kprintf("thread spawned\n");
+	switch_task();
+	kprintf("Back in main thread\n");
+
 	asm volatile("sti");
 
 	while (true)
diff --git a/src/kernel/multiboot.c b/src/kernel/multiboot.c
index c3a3a2e..d69f56c 100644
--- a/src/kernel/multiboot.c
+++ b/src/kernel/multiboot.c
@@ -15,7 +15,7 @@
 	TO_VIRT(mb.cmdline, char);
 
 	kprintf("mb.mods_addr = %d, 0x%x\n", mb.mods_addr, mb.mods_addr);
-	kassert((size_t)mb.mods_addr > 0xc0000000, "mb.mods_addr PHYSICAL");
+	kassert((size_t)mb.mods_addr >= 0xc0000000, "mb.mods_addr PHYSICAL");
 	for (int i = 0; i < mb.mods_count + 1; i++)
 	{
 		TO_VIRT(*(uint *)(mb.mods_addr+i), uint);
diff --git a/src/kernel/paging.c b/src/kernel/paging.c
index 4d0aa94..809d12c 100644
--- a/src/kernel/paging.c
+++ b/src/kernel/paging.c
@@ -5,9 +5,9 @@
 #include "log.h"
 #include "pic.h"
 
+#define NUM_FRAMES 0xffffffff / 0x1000 / 32
 /* frames bitset, 0 = free, 1 = used */
-static uint frames[0xffffffff / 0x1000 / 32];
-static ulong num_frames;
+static uint frames[NUM_FRAMES];
 
 static uint first_page_table[1024] __attribute__((aligned(4096)));
 uint kernel_page_directory[1024] __attribute__((aligned(4096)));
@@ -36,7 +36,7 @@
 
 static uint first_free_frame()
 {
-	for (int i = 0; i < num_frames / BITS; i++)
+	for (int i = 0; i < NUM_FRAMES / BITS; i++)
 	{
 		/*
 		 * If there are any zeroes, ~ will yield a non-zero result,
@@ -47,10 +47,13 @@
 
 		for (int j = 0; j < BITS; j++)
 		{
-			if ((frames[i] & 1 << j) == 0)
+			if ((frames[i] & (1 << j)) == 0)
 			{
 				/* found unused frame */
-				return i * BITS + j;
+				uint frame = i * BITS + j;
+				kprintf("first_free_frame returning %d\n", frame);
+//				kpanic("asdf");
+				return frame;
 			}
 		}
 	}
@@ -61,7 +64,7 @@
 
 void alloc_frame(uint *page_table_entry, bool user, bool writable)
 {
-	if (*page_table_entry >> 12)
+	if (*page_table_entry & 1)
 		return; /* frame already allocated */
 
 	uint frame = first_free_frame();
@@ -83,7 +86,7 @@
 
 	for (uint i = 0; i < 1024 * 0x1000; i += 0x1000)
 	{
-		set_frame(page + i);
+		set_frame(i);
 	}
 
 	dir[table] = 0b10000011;
@@ -93,7 +96,7 @@
 {
 	if (dir[table] >> 12)
 	{
-		return (uint *)(size_t)(dir[table] ^ 0xfff);
+		return (uint *)(size_t)PHYS_TO_VIRT((dir[table] ^ 0xfff));
 	}
 
 	uint *page_table = kmalloc_a(sizeof(uint[1024]));
@@ -129,6 +132,9 @@
 	uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
 
 	alloc_frame(&table[page], false, false);
+
+	kprintf("alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
+	return;
 }
 
 void alloc_kernel_page_range(uint *from, uint *to)
diff --git a/src/kernel/task.c b/src/kernel/task.c
index 3d27850..4e71174 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -1,22 +1,35 @@
 #include "task.h"
 #include "alloc.h"
 #include "io.h"
+#include "log.h"
 #include "paging.h"
 
 struct process processes[1024] = {0};
 struct ll_task_i *first_task = NULL, *last_task = NULL, *current_task = NULL;
+static uint next_task_id = 0;
 
-void init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip)
+void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip)
 {
 	asm volatile("cli");
 
+	kprintf("_init_tasks\n");
+
 	processes[0] = (struct process){
 		.exists = true,
 		.id = 0,
 		.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.
+		.last_stack_pos = 0xFFFFF000,
 	};
 	strcpy(processes[0].name, "kernel");
+	kprintf("in _init_tasks, strlen of 'kernel' is %d\n", strlen("kernel"));
 
 	first_task = last_task = current_task = malloc(sizeof(struct ll_task_i));
 
@@ -26,10 +39,11 @@
 		.esp = kernel_esp,
 		.ebp = kernel_ebp,
 		.eip = kernel_eip,
-		.kernel = true,
-		.page_directory = kernel_page_directory,
+		.id = next_task_id++,
 	};
 
+	kprintf("Returning from _init_tasks\n");
+
 	asm volatile("sti");
 }
 
@@ -51,7 +65,82 @@
 	return current_task->task.proc->id;
 }
 
-void spawn_thread(void (* function)(void *data), void *data)
+void spawn_thread(void (*function)())
 {
+	asm volatile("cli");
 
+	struct process *proc = current_task->task.proc;
+	// Virtual address of page directory (in kernel memory)
+	uint *dir_v = PHYS_TO_VIRT(proc->page_directory_p);
+	// Virtual location of new stack
+	uint new_stack_base_v = proc->last_stack_pos = proc->last_stack_pos - 0x1000;
+
+	// Alloc a new page in the current process mapping to the new stack
+	alloc_page(dir_v, (void *)new_stack_base_v);
+
+	// <TEST>: see if we can assign to the new stack memory (ie: did mapping succeed)
+	uint *base = (uint *)new_stack_base_v;
+
+	kprintf("base = 0x%x\n", base);
+
+	*base = 0;
+	kpanic("in spawn_thread\n");
+	// </TEST>
+
+	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;
+
+	task->proc = proc;
+	task->id = next_task_id++;
+	task->ebp = task->esp = new_stack_base_v;
+	task->eip = (uint)function;
+
+	last_task->next = ll_task;
+	last_task = ll_task;
+
+	asm volatile("sti");
+}
+
+extern void _switch_to_task(uint page_directory, uint eip, uint ebp, uint esp);
+
+void switch_to_task(struct task *task)
+{
+	_switch_to_task(task->proc->page_directory_p, task->eip, task->ebp,
+					task->esp);
+	__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)
+{
+	// sti is called in switch_to_task
+	asm volatile("cli");
+
+	kprintf("\nin _do_switch_task(%d, %d, %d)\n", eip, ebp, esp);
+
+	// save context for this task
+	current_task->task.ebp = ebp;
+	current_task->task.esp = esp;
+	current_task->task.eip = eip;
+
+	if (current_task->next == NULL)
+	{
+		// Start from the first task if there are more tasks, or just return
+		if (current_task == first_task)
+			return; // No context switch necessary
+
+		current_task = first_task;
+	}
+	else
+	{
+		// Continue the next task
+		current_task = current_task->next;
+	}
+
+	kprintf("Will switch to task id %d\n", current_task->task.id);
+
+	switch_to_task(&current_task->task);
 }
diff --git a/src/kernel/task.h b/src/kernel/task.h
index e70fd6d..c31162e 100644
--- a/src/kernel/task.h
+++ b/src/kernel/task.h
@@ -6,10 +6,15 @@
 struct process
 {
 	bool exists;
-	int id;
+	int id; // kernel uses pid 0, which cannot exit
 	int ring;
 	int uid;
 	char name[32];
+	uint page_directory_p;
+	// most recent (bottom) stack used by a task, next
+	// stack should be under this one.
+	// NOTE: must be PAGE ALIGNED
+	uint last_stack_pos;
 };
 
 struct task
@@ -18,8 +23,6 @@
 	struct process *proc;
 	uint stack_top_p; // stack frame PHYSICAL address
 	uint esp, ebp, eip;
-	uint *page_directory;
-	bool kernel;
 };
 
 struct ll_task_i
@@ -31,7 +34,7 @@
 // extern struct process processes[1024];
 // extern struct ll_task_i *first_task, *current_task;
 
-void init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip);
+extern void init_tasks();
 struct process *get_process(uint pid);
 
 int get_process_id();
@@ -40,4 +43,5 @@
 // For compatibility I guess
 #define getpid get_process_id
 
-void spawn_thread(void (* function)(void *data), void *data);
+void spawn_thread(void (*function)());
+extern void switch_task();
diff --git a/src/kernel/task_api.s b/src/kernel/task_api.s
new file mode 100644
index 0000000..686ddaa
--- /dev/null
+++ b/src/kernel/task_api.s
@@ -0,0 +1,39 @@
+	[bits 32]
+	[extern _do_switch_task]
+	[global switch_task]
+switch_task:	
+	pusha 						; Save everything
+	push esp					; Arguments for _do_switch_task(eip, ebp, esp)
+	push ebp
+	push .after
+	call _do_switch_task
+.after:
+	popa						; Reset everything
+	xor eax, eax				; Return 0
+	ret
+
+	[global _switch_to_task]
+_switch_to_task:				; (page_directory, eip, ebp, esp)
+	add esp, 4					; We don't care about the return address
+	pop eax 					; Instruction pointer
+	pop ebp 					; Frame pointer
+	pop ebx 					; Stack pointer
+	pop ecx 					; Page directory
+
+	mov esp, ebx 				; Reset old stack
+
+	mov cr3, ecx 				; Set page directory
+	sti
+	jmp eax 					; Jump back to code
+
+	[extern _init_tasks]
+	[global init_tasks]
+init_tasks:
+	lea eax, [esp + 4] 			; Stack pointer before call
+	mov ebx, [esp] 				; Return address
+	push ebx					; eip
+	push ebp					; ebp
+	push eax 					; esp
+	call _init_tasks
+	add esp, 12
+	ret