Fix paging #PF, simplify init_tasks

Unsure what fixed the paging #PF in init_tasks, but allocating a page
now works as expected. Originally a #PF would occur if alloc_page was
called after a certain point in init_tasks.
diff --git a/src/kernel/x86_32/.gdbinit b/src/kernel/x86_32/.gdbinit
deleted file mode 100644
index 54e4e4c..0000000
--- a/src/kernel/x86_32/.gdbinit
+++ /dev/null
@@ -1,2 +0,0 @@
-file kernel.elf
-target remote localhost:1234
diff --git a/src/kernel/x86_32/boot.s b/src/kernel/x86_32/boot.s
index 047b326..9828985 100644
--- a/src/kernel/x86_32/boot.s
+++ b/src/kernel/x86_32/boot.s
@@ -13,7 +13,7 @@
 	;; Index in page directory
 KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22)
 
-STACK_SIZE equ 0x4000
+STACK_SIZE equ 0x1000
 
 
 
@@ -23,7 +23,8 @@
 page_directory:	
 	dd 0b010000011				; Identity map first 4 megs
 	times (KERNEL_PAGE_NUMBER - 1) dd 0
-	dd 0b010000011 				; Map kernel memory to zero page too 
+	dd 0b010000011 				; Map kernel memory (4 megs) to zero
+								; page too				
 	times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0
 
 gdt:
diff --git a/src/kernel/x86_32/faults.c b/src/kernel/x86_32/faults.c
index e7c4180..761558c 100644
--- a/src/kernel/x86_32/faults.c
+++ b/src/kernel/x86_32/faults.c
@@ -12,8 +12,22 @@
 
 #define ADD_INTERRUPT(sym, num) add_interrupt_handler(num, sym##_h)
 
-DECLARE_INTERRUPT(gp, "#GP")
-DECLARE_INTERRUPT(pf, "#PF")
+DECLARE_INTERRUPT(gp, "#GP");
+
+static void pf_h(struct registers *regs)
+{
+	uint err = regs->error_code;
+
+	kprintf(ERROR "Fault #PF: eip=0x%x, err=0x%x\n", regs->eip, err);
+	kprintf("\tDue to: %c%c%c%c\n",
+			err & 1 ? 'P' : ' ',
+			err & (1<<1) ? 'W' : ' ',
+			err & (1<<2) ? 'U' : ' ',
+			err & (1<<4) ? 'I' : ' ');
+
+	asm("cli");
+	kpanic("#PF");
+}
 
 void init_faults()
 {
diff --git a/src/kernel/x86_32/log.c b/src/kernel/x86_32/log.c
index 0ea6822..9f0807f 100644
--- a/src/kernel/x86_32/log.c
+++ b/src/kernel/x86_32/log.c
@@ -72,7 +72,6 @@
 {
 	if (!condition)
 	{
-		vga_set_color(LIGHT_RED, BLACK);
 		kprintf(ERROR "ASSERTION FAILED: %s:%d\n%s\n", file, line, message);
 
 		while (1)
diff --git a/src/kernel/x86_32/main.c b/src/kernel/x86_32/main.c
index 17a54d7..4d3d868 100644
--- a/src/kernel/x86_32/main.c
+++ b/src/kernel/x86_32/main.c
@@ -66,9 +66,22 @@
 	asm("sti");
 
 	init_tasks();
+	kprintf(OKAY "Tasks initialized\n");
 	init_sync();
 
+#ifdef TEST_PAGING
+	test_paging();
+#endif
+
+#ifdef TEST_THREADS
+	kprintf(DEBUG "Spawning test thread\n");
+	spawn_thread(other_thread, NULL);
+
+	greet();
+#endif
+
 	pci_init();
+	kprintf(OKAY "PCI initialized\n");
 
 	// Register PCI drivers
 	ide_register();
@@ -77,12 +90,6 @@
 
 	kprintf(OKAY "Loaded PCI device drivers\n");
 
-#ifdef TEST_THREADS
-	spawn_thread(other_thread, NULL);
-
-	greet();
-#endif
-
 #ifdef TEST_PCI
 	pci_print_devices();
 	pci_print_drivers();
diff --git a/src/kernel/x86_32/paging.c b/src/kernel/x86_32/paging.c
index f959a92..c77f499 100644
--- a/src/kernel/x86_32/paging.c
+++ b/src/kernel/x86_32/paging.c
@@ -61,7 +61,7 @@
 				/* found unused frame */
 				uint frame = i * BITS + j;
 				kprintf(DEBUG "first_free_frame returning %d\n", frame);
-//				kpanic("asdf");
+
 				return frame;
 			}
 		}
@@ -103,10 +103,12 @@
 
 uint *get_or_create_table(uint *dir, uint table, bool user, bool rw)
 {
-	// If used AND NOT 4mb page (see figure 4-4, page 115 of Intel
+	// If used AND NOT 4mb page (see figure 4-4, page 114 of Intel
 	// manual volume 3)
-	if (dir[table] & 1 && dir[table] ^ 1 << 7)
+	// bit 0 = used; bit 7 = 4MB?
+	if (dir[table] & 1 && dir[table] ^ (1 << 7))
 	{
+		// 12 LSBs are metadata
 		return (uint *)(size_t)PHYS_TO_VIRT((dir[table] & ~0xfff));
 	}
 
@@ -146,11 +148,13 @@
 	table[page] = 0;
 }
 
+// TODO: This entire function seems wrong.
 void map_page_to(uint *dir, void *virt, void *frame_p, bool writable, bool user)
 {
 	uint page = ((size_t)virt / 0x1000) % 1024;
 	uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
 
+	// TODO: is the xor here correct?
 	table[page] = (((uint)frame_p) ^ 0xfff) | 1 | writable << 1 | user << 2;
 }
 
@@ -164,12 +168,12 @@
 	// Page number % pages per table
 	uint page = ((size_t)virt / 0x1000) % 1024;
 	uint *table = get_or_create_table(dir, (size_t)virt >> 22, false, false);
-	kprintf(DEBUG "table = 0x%x (virt)\n", table);
-	kprintf(DEBUG "dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
+	// kprintf(DEBUG "table = 0x%x (virt)\n", table);
+	// kprintf(DEBUG "dir entry = 0x%x\n", dir[(size_t)virt >> 22]);
 
 	alloc_frame(&table[page], false, false);
 
-	kprintf(DEBUG "alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
+	// kprintf(DEBUG "alloc_page table[page] = %d (0x%x)\n", table[page], table[page]);
 	return;
 }
 
@@ -231,13 +235,20 @@
 	map_4mb(kernel_page_directory, (size_t)KERNEL_VIRTUAL_BASE, 0, false,
 			false);
 
-	load_page_directory((uint)kernel_page_directory - 0xC0000000);
-
-	add_interrupt_handler(14, page_fault);
+	load_page_directory(VIRT_TO_PHYS(kernel_page_directory));
 }
 
-void page_fault(struct registers *regs)
+void test_paging()
 {
-	kprintf(ERROR "Page fault! eip = %d\n", regs->eip);
-	kpanic("Page fault");
+	// a random page base address
+	uint *base = (uint *)0xFFFFFE000;
+
+	kprintf(INFO "Allocating page (expect frame 1024)\n");
+	alloc_page(kernel_page_directory, base);
+
+	kprintf(INFO "Writing 10 words to page\n");
+	for (int i = 0; i < 10; i++)
+	{
+		base[i] = i;
+	}
 }
diff --git a/src/kernel/x86_32/paging.h b/src/kernel/x86_32/paging.h
index e264356..c06b3a2 100644
--- a/src/kernel/x86_32/paging.h
+++ b/src/kernel/x86_32/paging.h
@@ -11,13 +11,19 @@
 /* defined in switch_table.s */
 extern uint load_page_directory(uint table_address);
 extern void enable_paging();
+extern void invalidate_page(void *address);
 extern uint kernel_page_directory[1024];
 
 void init_paging();
 
 void map_page_to(uint *dir, void *virt, void *frame_p, bool writable, bool user);
 void alloc_frame(uint *page_table_entry, bool user, bool writable);
+
+/* Map the 4kb of virtual memory starting at `page` to a physical page
+ * in the page directory `dir` (pointer to page directory in virtual
+ * memory) */
 void alloc_page(uint *dir, uint *page);
 void alloc_kernel_page(uint *page);
-void page_fault(struct registers *regs);
 uint *new_page_directory_v();
+
+void test_paging();
diff --git a/src/kernel/x86_32/switch_table.s b/src/kernel/x86_32/switch_table.s
index c8e6260..e7d80f9 100644
--- a/src/kernel/x86_32/switch_table.s
+++ b/src/kernel/x86_32/switch_table.s
@@ -7,9 +7,8 @@
 	mov cr3, ecx
 	ret
 
-	[global enable_paging]
-enable_paging:
-	mov ecx, cr0
-	or eax, 0x80000000
-	mov cr0, ecx
+	[global invalidate_page]
+invalidate_page: 				; void (void *page)
+	mov eax, [esp + 4]
+	invlpg [eax]
 	ret
diff --git a/src/kernel/x86_32/task.c b/src/kernel/x86_32/task.c
index 1ec1337..2f8c3a8 100644
--- a/src/kernel/x86_32/task.c
+++ b/src/kernel/x86_32/task.c
@@ -5,28 +5,14 @@
 #include "paging.h"
 #include "pic.h"
 
-struct process processes[1024] = {0};
-struct ll_task_i *first_task = NULL, *last_task = NULL, *current_task = NULL;
+static struct process processes[1024] = {0};
+static struct ll_task_i *first_task = NULL, *last_task = NULL, *current_task = NULL;
 static uint next_task_id = 0;
 
 bool tasks_initialized = false;
 
-void _init_tasks(struct registers *regs);
-
 void init_tasks()
 {
-	add_interrupt_handler(INIT_TASKS_INTERRUPT, _sys_init_tasks_h);
-
-	asm("int $0x81");
-}
-
-void _sys_init_tasks_h(struct registers *regs)
-{
-	_init_tasks(regs);
-}
-
-void _init_tasks(struct registers *regs)
-{
 	processes[0] = (struct process){
 		.exists = true,
 		.id = 0,
@@ -49,9 +35,12 @@
 	first_task->next = NULL;
 	first_task->prev = NULL;
 	memset(&first_task->task, 0, sizeof(struct task));
+	// state will be filled in upon task switch.  TODO: task switch
+	// before spawning thread (or fill in CS, etc manually) to avoid
+	// #GP on task switch. New threads based on parent task
 	first_task->task = (struct task){
 		.proc = &processes[0],
-		.state = *regs,
+		.state = { 0 },
 		.id = next_task_id++,
 		.waiting = false,
 	};
@@ -89,17 +78,18 @@
 
 	// Virtual location of new stack, with space reserved for argument
 	// and return address to kill_this_thread().
-	uint new_stack_base_v = proc->last_stack_pos;
+	uint *new_stack_base_v = (uint *)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 *)proc->last_stack_pos);
 
-	kprintf(INFO "new_stack_base_v = %p\n", new_stack_base_v);
-	new_stack_base_v -= sizeof(uint);
-	*((uint *)new_stack_base_v) = (size_t)data;
-	new_stack_base_v -= sizeof(uint);
-	*((uint *)new_stack_base_v) = (size_t)&kill_this_thread;
+	kprintf(INFO "new_stack_base_v = %p, last_stack_pos = %p\n",
+			new_stack_base_v, proc->last_stack_pos);
+
+	// Write data argument and return pointer to new threads stack
+	new_stack_base_v[-1] = (size_t)data;
+	new_stack_base_v[-2] = (size_t)&kill_this_thread;
 
 	kprintf(DEBUG "Set stack\n");
 
@@ -113,7 +103,7 @@
 	// Namely a new TID
 	task->id = next_task_id++;
 	// And stack, frame, and instruction pointers
-	task->state.ebp = task->state.esp = new_stack_base_v;
+	task->state.ebp = task->state.esp = (uint)(new_stack_base_v - 2);
 	task->state.eip = (uint)function;
 	task->waiting = false;
 
@@ -162,6 +152,8 @@
 	asm("sti");
 }
 
+extern uint _get_cr3();
+
 extern void _switch_to_task(uint page_directory, struct registers ctx);
 #if 0
 {
@@ -174,6 +166,8 @@
 
 void switch_to_task(struct task *task)
 {
+	kprintf(DEBUG "switch_to_task cr3=0x%x\n", task->proc->page_directory_p);
+
 	_switch_to_task(task->proc->page_directory_p, task->state);
 	__builtin_unreachable();
 }
@@ -183,7 +177,9 @@
 	// Resetting eflags in _switch_to_task iret will switch this back
 	asm("cli");
 
-	kprintf(DEBUG "switching tasks\n");
+	kprintf(DEBUG "switching tasks, alleged cr3=0x%x, real cr3=0x%x\n",
+			current_task->task.proc->page_directory_p,
+			_get_cr3());
 
 	// save context for this task
 	current_task->task.state = regs;
diff --git a/src/kernel/x86_32/task_api.s b/src/kernel/x86_32/task_api.s
index fce9811..44c0b4e 100644
--- a/src/kernel/x86_32/task_api.s
+++ b/src/kernel/x86_32/task_api.s
@@ -9,3 +9,8 @@
 	popad						; Then the rest of the registers
 	add esp, 8					; Then IRQ # and error #
 	iret						; And finally the saved state
+
+	[global _get_cr3]
+_get_cr3:
+	mov eax, cr3
+	ret
diff --git a/src/kernel/x86_32/x86_32.jmk b/src/kernel/x86_32/x86_32.jmk
index 9a67295..669e60a 100644
--- a/src/kernel/x86_32/x86_32.jmk
+++ b/src/kernel/x86_32/x86_32.jmk
@@ -1,8 +1,10 @@
 # -*- tcl -*-
 
+cflags -DTEST_THREADS
 ldflags -T[pwd]/link.ld -melf_i386
 asmflags -felf -Fdwarf
-set qemuflags "-drive file=hd0_ext2.img,format=raw"
+set qemuflags ""
+# "-drive file=hd0_ext2.img,format=raw"
 
 depends sys $root/src/libsys libsys.a
 depends initrd $root/boot/initrd initrd.img
@@ -45,15 +47,15 @@
 	[lib sys]
 
 rule debug-wait kernel.elf {
-	shell "qemu-system-i386 -s -S $::qemuflags -kernel kernel.efl"
+	shell "qemu-system-i386 -s -S $::qemuflags -kernel kernel.elf"
 }
 rule debug kernel.elf {
-	shell "qemu-system-i386 -s -S $::qemuflags -kernel kernel.efl"
+	shell "qemu-system-i386 -s -S $::qemuflags -kernel kernel.elf &"
 	shell "echo run target remote localhost:1234 to connect to qemu"
 	shell "gdb $::first_src"
 	shell "pkill qemu-system-i386"
 }
 
-rule qemu "kernel.elf hd0_$::options(FS).img" {
+rule qemu "kernel.elf" {
 	shell "qemu-system-i386 $::qemuflags -d cpu_reset -monitor stdio -kernel kernel.elf -no-reboot"
 }