Add paging
diff --git a/src/.clang-format b/src/.clang-format
new file mode 100644
index 0000000..ef3f3d7
--- /dev/null
+++ b/src/.clang-format
@@ -0,0 +1,4 @@
+---
+BasedOnStyle: Microsoft
+UseTab: Always
+ColumnLimit: 80
diff --git a/src/Makefile b/src/Makefile
index 6ce6c27..b9f1708 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,14 +5,16 @@
 			vga.o \
 			gdt_flush.o \
 			idt.o \
-			interrupts.o \
 			log.o \
 			irq.o \
 			pic.o \
-			timer.o
+			timer.o \
+			paging.o \
+			switch_table.o
 CFLAGS = -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 -O2 -g
 LDFLAGS = -Tlink.ld -melf_i386
 ASMFLAGS = -felf
+QEMUFLAGS = -d cpu_reset
 
 kernel.elf: $(SOURCES)
 	ld $(LDFLAGS) -o $@ $^
@@ -27,10 +29,10 @@
 	@pkill qemu-system-i38
 
 qemu: kernel.elf
-	qemu-system-i386 -monitor stdio -kernel kernel.elf
+	qemu-system-i386 $(QEMUFLAGS) -monitor stdio -kernel kernel.elf -no-reboot
 
 qemu-iso: install
-	qemu-system-i386 -monitor stdio ../bin/bluejay.iso
+	qemu-system-i386 $(QEMUFLAGS) -monitor stdio ../bin/bluejay.iso
 
 .s.o:
 	nasm $(ASMFLAGS) $<
diff --git a/src/descriptor_tables.c b/src/descriptor_tables.c
index 86e554a..916a1ae 100644
--- a/src/descriptor_tables.c
+++ b/src/descriptor_tables.c
@@ -1,13 +1,14 @@
 #include "descriptor_tables.h"
-#include "vga.h"
 #include "io.h"
 #include "log.h"
 #include "pic.h"
+#include "vga.h"
 
 extern void gdt_flush(uint gdt);
 extern void idt_flush(uint idt);
 
-static void gdt_set_gate(uint i, uint base, uint limit, uchar access, uchar gran);
+static void gdt_set_gate(uint i, uint base, uint limit, uchar access,
+						 uchar gran);
 static void idt_set_gate(uchar num, uint base, ushort selector, uchar flags);
 
 struct gdt_entry gdt_entries[5];
@@ -17,13 +18,15 @@
 struct idt_pointer idt_pointer;
 
 static void (*isrs[32])() = {
-    isr0,  isr1,  isr2,  isr3,  isr4,  isr5,  isr6,  isr7,  isr8,  isr9,  isr10,
-    isr11, isr12, isr13, isr14, isr15, isr16, isr17, isr18, isr19, isr20, isr21,
-    isr22, isr23, isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31};
+	isr0,  isr1,  isr2,	 isr3,	isr4,  isr5,  isr6,	 isr7,	isr8,  isr9,  isr10,
+	isr11, isr12, isr13, isr14, isr15, isr16, isr17, isr18, isr19, isr20, isr21,
+	isr22, isr23, isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31};
 
-static void (*irqs[16])() = {irq0,  irq1,  irq2,  irq3, irq4,  irq5,
-                             irq6,  irq7,  irq8,  irq9, irq10, irq11,
-                             irq12, irq13, irq14, irq15};
+static void (*irqs[16])() = {irq0,	irq1,  irq2,  irq3, irq4,  irq5,
+							 irq6,	irq7,  irq8,  irq9, irq10, irq11,
+							 irq12, irq13, irq14, irq15};
+
+extern void (*interrupt_handlers[256])(struct registers);
 
 void init_gdt()
 {
@@ -31,21 +34,23 @@
 	gdt_pointer.limit = sizeof(struct gdt_entry) * 5 - 1;
 	gdt_pointer.base = (uint)&gdt_entries;
 
-	gdt_set_gate(0, 0, 0, 0, 0);          // Null segment
-	gdt_set_gate(1, 0, ~0, 0x9a, 0xcf);   // Code segment
-	gdt_set_gate(2, 0, ~0, 0x92, 0xcf);   // Data segment
-	gdt_set_gate(3, 0, ~0, 0xfa, 0xcf);   // User mode code segment
-	gdt_set_gate(4, 0, ~0, 0xf2, 0xcf);   // User mode data segment
+	gdt_set_gate(0, 0, 0, 0, 0);		// Null segment
+	gdt_set_gate(1, 0, ~0, 0x9a, 0xcf); // Code segment
+	gdt_set_gate(2, 0, ~0, 0x92, 0xcf); // Data segment
+	gdt_set_gate(3, 0, ~0, 0xfa, 0xcf); // User mode code segment
+	gdt_set_gate(4, 0, ~0, 0xf2, 0xcf); // User mode data segment
 
 	for (volatile uint i = 0; i < 0x1000; i++)
-	{} // waste some time, for some reason this helps
-	
-	gdt_flush((uint) &gdt_pointer);
+	{
+	} // waste some time, for some reason this helps
+
+	gdt_flush((uint)&gdt_pointer);
 
 	vga_write("GDT Initialized\n");
 }
 
-static void gdt_set_gate(uint i, uint base, uint limit, uchar access, uchar gran)
+static void gdt_set_gate(uint i, uint base, uint limit, uchar access,
+						 uchar gran)
 {
 	struct gdt_entry *e = &gdt_entries[i];
 
@@ -72,7 +77,6 @@
 	vga_set_color(CYAN, BLACK);
 	for (int i = 0; i < 16; i++)
 	{
-		kprintf("Setting gate irq=%d,\tint=%d\n", i, IRQ_TO_INT(i));
 		idt_set_gate(IRQ_TO_INT(i), (uint)irqs[i], 0x08, 0x8e);
 	}
 	vga_set_color(WHITE, BLACK);
@@ -103,4 +107,5 @@
 {
 	init_gdt();
 	init_idt();
+	memset(interrupt_handlers, 0, sizeof(interrupt_handlers));
 }
diff --git a/src/descriptor_tables.h b/src/descriptor_tables.h
index d1b68bc..b35f670 100644
--- a/src/descriptor_tables.h
+++ b/src/descriptor_tables.h
@@ -8,36 +8,33 @@
 	ushort base_low;
 	uchar base_middle;
 
-	union
-	{
+	union {
 		struct
 		{
-			uint a_p    : 1;
-			uint a_dpl  : 2;
-			uint a_dt   : 1;
+			uint a_p : 1;
+			uint a_dpl : 2;
+			uint a_dt : 1;
 			uint a_type : 4;
 		} __attribute__((packed));
 
 		uchar access;
 	};
 
-	union
-	{
+	union {
 		struct
 		{
-			uint g_g    : 1;
-			uint g_d    : 1;
+			uint g_g : 1;
+			uint g_d : 1;
 			uint g_zero : 2; /* includes A */
-			uint g_len  : 4;
+			uint g_len : 4;
 		} __attribute__((packed));
-		
+
 		uchar granularity;
 	};
 
 	uchar base_high;
 } __attribute__((packed));
 
-
 struct gdt_pointer
 {
 	/* Upper 16 bits of selector limits */
@@ -52,18 +49,17 @@
 	ushort selector;
 	uchar zero;
 
-	union
-	{
+	union {
 		struct
 		{
-			uchar f_p     : 1;
-			uchar f_dpl   : 2;
+			uchar f_p : 1;
+			uchar f_dpl : 2;
 			uchar f_const : 5;
 		} __attribute__((packed));
-		
+
 		uchar flags;
 	};
-	
+
 	ushort base_high;
 } __attribute__((packed));
 
@@ -125,7 +121,6 @@
 extern void irq14();
 extern void irq15();
 
-
 void init_descriptor_tables();
 void init_idt();
 void init_gdt();
diff --git a/src/idt.s b/src/idt.s
index 6ded21b..3e2ce5d 100644
--- a/src/idt.s
+++ b/src/idt.s
@@ -10,8 +10,8 @@
 	[global isr%1]
 isr%1:
 	cli
-	push byte 0
-	push byte %1
+	push 0
+	push %1
 	jmp isr_common
 %endmacro
 
diff --git a/src/interrupts.c b/src/interrupts.c
deleted file mode 100644
index c1743d1..0000000
--- a/src/interrupts.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "kint.h"
-#include "vga.h"
-#include "registers.h"
-
-void isr_handler(struct registers regs)
-{
-	vga_write("Interrupt triggered! ");
-	vga_putx(regs.interrupt_number);
-	vga_write("\n");
-}
diff --git a/src/io.c b/src/io.c
index 1b35f71..52e5d04 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1,22 +1,21 @@
 #include "io.h"
 
-
 void outb(ushort port, uchar val)
 {
-	asm volatile("outb %1, %0" : : "dN" (port), "a" (val));
+	asm volatile("outb %1, %0" : : "dN"(port), "a"(val));
 }
 
 uchar inb(ushort port)
 {
 	uchar ret;
-	asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
+	asm volatile("inb %1, %0" : "=a"(ret) : "dN"(port));
 	return ret;
 }
 
 ushort inw(ushort port)
 {
 	ushort ret;
-	asm volatile("inw %1, %0" : "=a" (ret) : "dN" (port));
+	asm volatile("inw %1, %0" : "=a"(ret) : "dN"(port));
 	return ret;
 }
 
@@ -26,6 +25,7 @@
 	{
 		((uchar *)s)[i] = c;
 	}
+	return s;
 }
 
 void *memcpy(void *dest, const void *src, size_t n)
@@ -34,9 +34,10 @@
 	{
 		((uchar *)dest)[i] = ((uchar *)src)[i];
 	}
+	return dest;
 }
 
 void io_wait()
 {
-	asm volatile("outb %0, $0x80" :: "a"(0));
+	asm volatile("outb %0, $0x80" ::"a"(0));
 }
diff --git a/src/irq.s b/src/irq.s
index 9806b1e..e340a61 100644
--- a/src/irq.s
+++ b/src/irq.s
@@ -4,8 +4,8 @@
 	[global irq%1]
 irq%1:
 	cli
-	push byte 0 				; Error code
-	push byte %2				; Interrupt number
+	push 0		 				; Error code
+	push %2						; Interrupt number
 	jmp irq_common
 %endmacro
 
diff --git a/src/kint.h b/src/kint.h
index 0184443..abe7660 100644
--- a/src/kint.h
+++ b/src/kint.h
@@ -5,7 +5,7 @@
 typedef unsigned int uint;
 typedef unsigned long ulong;
 
-typedef unsigned long long size_t;
+typedef unsigned long size_t;
 
 typedef uchar bool;
 
@@ -14,3 +14,5 @@
 	false = 0,
 	true,
 };
+
+#define NULL ((void *)0)
diff --git a/src/log.c b/src/log.c
index 19959e7..0766a60 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,7 +1,7 @@
 #include "log.h"
 #include "kint.h"
-#include "vga.h"
 #include "stdarg.h"
+#include "vga.h"
 
 void kprintf(const char *format, ...)
 {
@@ -13,26 +13,23 @@
 		if (*format == '%')
 		{
 			format++;
-			
+
 			switch (*format)
 			{
-			case 'd':
-			{
-				uint x = (uint) va_arg(args, uint);
+			case 'd': {
+				uint x = (uint)va_arg(args, uint);
 				vga_putd(x);
 				break;
 			}
-				
-			case 'x':
-			{
+
+			case 'x': {
 				// consider hex always unsigned
-				uint x = (uint) va_arg(args, uint);
+				uint x = (uint)va_arg(args, uint);
 				vga_putx(x);
 				break;
 			}
 
-			case 's':
-			{
+			case 's': {
 				char *s = va_arg(args, char *);
 				vga_write(s);
 				break;
@@ -50,14 +47,16 @@
 	va_end(args);
 }
 
-void kassert_int(bool condition, const char *message, const char *file, const int line)
+void kassert_int(bool condition, const char *message, const char *file,
+				 const int line)
 {
 	if (!condition)
 	{
 		vga_set_color(LIGHT_RED, BLACK);
 		kprintf("ASSERTION FAILED: %s:%d\n%s\n", file, line, message);
-		
+
 		while (1)
-		{}
+		{
+		}
 	}
 }
diff --git a/src/log.h b/src/log.h
index 48da93e..fe5dcd9 100644
--- a/src/log.h
+++ b/src/log.h
@@ -3,6 +3,10 @@
 #include "kint.h"
 
 void kprintf(const char *format, ...);
-void kassert_int(bool condition, const char *message, const char *file, const int line);
+void kassert_int(bool condition, const char *message, const char *file,
+				 const int line);
 
 #define kassert(cond, msg) kassert_int((cond), (msg), __FILE__, __LINE__)
+#define kpanic(msg)                                                            \
+	kassert(false, msg);                                                       \
+	__builtin_unreachable()
diff --git a/src/main.c b/src/main.c
index 8d2783f..84f5a79 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,8 +1,9 @@
-#include "vga.h"
-#include "log.h"
-#include "io.h"
 #include "descriptor_tables.h"
+#include "io.h"
+#include "log.h"
 #include "timer.h"
+#include "vga.h"
+#include "paging.h"
 
 int kmain(void *mboot)
 {
@@ -17,12 +18,23 @@
 	vga_write("Setup complete!\n");
 	vga_set_color(WHITE, BLACK);
 
+	init_timer(20);
+
+	initialize_paging();
 	asm volatile("sti");
 
-	init_timer(50);
 
-	while (1)
-	{}
-	
+#ifdef TEST_PAGE_FAULT
+	kprintf("Causing page fault:\n");
+
+	volatile uint *ptr = (uint *) 0xa0000000;
+	volatile uint cause_page_fault = *ptr;
+
+	kprintf("Should have caused page fault: %d...\n", cause_page_fault);
+#endif
+
+	while (true)
+		asm volatile("hlt");
+
 	return 0xCAFEBABE;
 }
diff --git a/src/paging.c b/src/paging.c
new file mode 100644
index 0000000..128de4e
--- /dev/null
+++ b/src/paging.c
@@ -0,0 +1,142 @@
+#include "paging.h"
+#include "io.h"
+#include "kint.h"
+#include "log.h"
+#include "pic.h"
+
+extern uint end;
+static size_t alloc_base = (size_t)&end;
+
+/* frames bitset, 0 = free, 1 = used */
+static uint *frames;
+static ulong num_frames;
+
+static uint first_page_table[1024] __attribute__((aligned(4096)));
+static uint *page_directory[1024] __attribute__((aligned(4096)));
+
+static uint ***current_directory;
+
+void *_kmalloc(size_t size, bool align, void **phys)
+{
+	if (align && (alloc_base & 0xfff)) // if not yet aligned
+	{
+		alloc_base &= ~0xfff;
+		alloc_base += 0x1000;
+	}
+
+	if (phys)
+	{
+		*phys = (void *)alloc_base;
+	}
+
+	size_t addr = alloc_base;
+	alloc_base += size;
+	return (void *)addr;
+}
+
+void *kmalloc(size_t size)
+{
+	return _kmalloc(size, false, NULL);
+}
+
+void *kmalloc_a(size_t size)
+{
+	return _kmalloc(size, true, NULL);
+}
+
+void *kmalloc_ap(size_t size, void **p)
+{
+	return _kmalloc(size, true, p);
+}
+
+/* frame utils */
+
+#define BITS 32
+
+static void set_frame(size_t frame_addr)
+{
+	uint frame = frame_addr / 0x1000; // page aligned
+	frames[frame / BITS] |= 1 << (frame % BITS);
+}
+
+static bool test_frame(size_t frame_addr)
+{
+	uint frame = frame_addr / 0x1000; // page aligned
+	return frames[frame / BITS] & 1 << (frame % BITS);
+}
+
+static void clear_frame(size_t frame_addr)
+{
+	uint frame = frame_addr / 0x1000; // page aligned
+	frames[frame / BITS] &= ~(1 << (frame % BITS));
+}
+
+static uint first_free_frame()
+{
+	for (int i = 0; i < num_frames / BITS; i++)
+	{
+		/*
+		 * If there are any zeroes, ~ will yield a non-zero result,
+		 * meaning that there are pages free. Otherwise, check next set
+		 */
+		if (!~frames[i])
+			continue;
+
+		for (int j = 0; j < BITS; j++)
+		{
+			if ((frames[i] & 1 << j) == 0)
+			{
+				/* found unused frame */
+				return i * BITS + j;
+			}
+		}
+	}
+
+	/* did not find a free frame, panic */
+	kpanic("first_free_frame failed! no free frames");
+}
+
+void alloc_frame(uint *page, bool for_kernel, bool writable)
+{
+	if (*page >> 12)
+		return; /* frame already allocated */
+
+	uint frame = first_free_frame();
+	//	kprintf("first_free_frame found %d\n", frame);
+	set_frame(frame * 0x1000); /* mark as mapped */
+}
+
+void free_frame(uint page)
+{
+	clear_frame(page / 0x1000);
+}
+
+/* paging stuff */
+
+void initialize_paging()
+{
+	for (int i = 0; i < 1024; i++)
+	{
+		page_directory[i] = (uint *) 0b010; // kernel, rw, not present
+	}
+
+	for (int i = 0; i < 1024; i++)
+	{
+		first_page_table[i] = (i * 0x1000) | 3;
+	}
+
+	page_directory[0] = (uint *) (((size_t) (uint *) first_page_table) | 3);
+
+	kprintf("Set up page directory[0], %x\n", (uint)first_page_table);
+
+	load_page_directory((uint) page_directory);
+	enable_paging();
+
+	add_interrupt_handler(14, page_fault);
+}
+
+void page_fault(struct registers *regs)
+{
+	kprintf("Page fault! eip = %d\n", regs->eip);
+	kpanic("Page fault");
+}
diff --git a/src/paging.h b/src/paging.h
new file mode 100644
index 0000000..7c5000e
--- /dev/null
+++ b/src/paging.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "kint.h"
+#include "registers.h"
+
+/* defined in switch_table.s */
+extern uint load_page_directory(uint table_address);
+extern void enable_paging();
+
+void *_kmalloc(size_t size, bool align, void **phys);
+void *kmalloc(size_t size);
+void *kmalloc_a(size_t size);
+void *kmalloc_ap(size_t size, void **p);
+
+void initialize_paging();
+
+void page_fault(struct registers *regs);
diff --git a/src/pic.c b/src/pic.c
index f5355a8..1c96543 100644
--- a/src/pic.c
+++ b/src/pic.c
@@ -1,21 +1,20 @@
 #include "pic.h"
-#include "log.h"
 #include "io.h"
+#include "log.h"
 
-#define ICW1_ICW4	0x01		/* ICW4 (not) needed */
-#define ICW1_SINGLE	0x02		/* Single (cascade) mode */
-#define ICW1_INTERVAL4	0x04		/* Call address interval 4 (8) */
-#define ICW1_LEVEL	0x08		/* Level triggered (edge) mode */
-#define ICW1_INIT	0x10		/* Initialization - required! */
- 
-#define ICW4_8086	0x01		/* 8086/88 (MCS-80/85) mode */
-#define ICW4_AUTO	0x02		/* Auto (normal) EOI */
-#define ICW4_BUF_SLAVE	0x08		/* Buffered mode/slave */
-#define ICW4_BUF_MASTER	0x0C		/* Buffered mode/master */
-#define ICW4_SFNM	0x10		/* Special fully nested (not) */
+#define ICW1_ICW4 0x01		/* ICW4 (not) needed */
+#define ICW1_SINGLE 0x02	/* Single (cascade) mode */
+#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
+#define ICW1_LEVEL 0x08		/* Level triggered (edge) mode */
+#define ICW1_INIT 0x10		/* Initialization - required! */
 
+#define ICW4_8086 0x01		 /* 8086/88 (MCS-80/85) mode */
+#define ICW4_AUTO 0x02		 /* Auto (normal) EOI */
+#define ICW4_BUF_SLAVE 0x08	 /* Buffered mode/slave */
+#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
+#define ICW4_SFNM 0x10		 /* Special fully nested (not) */
 
-void (* interrupt_handlers[256])(struct registers);
+void (*interrupt_handlers[256])(struct registers *);
 
 void pic_send_eoi(uchar interrupt)
 {
@@ -29,29 +28,37 @@
 {
 	pic_send_eoi(regs.interrupt_number);
 
-	kprintf("irq_handler called with interrupt %d\n", regs.interrupt_number);
-
 	if (interrupt_handlers[regs.interrupt_number])
-		interrupt_handlers[regs.interrupt_number](regs);
+		interrupt_handlers[regs.interrupt_number](&regs);
+	else
+		kprintf("Unhandled hardware interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
 }
 
-void add_interrupt_handler(uchar interrupt, void (* handler)(struct registers))
+void isr_handler(struct registers regs)
+{
+	if (interrupt_handlers[regs.interrupt_number])
+		interrupt_handlers[regs.interrupt_number](&regs);
+	else
+		kprintf("Unhandled interrupt: %d, called from %d\n", regs.interrupt_number, regs.eip);
+}
+
+void add_interrupt_handler(uchar interrupt, void (*handler)(struct registers *))
 {
 	interrupt_handlers[interrupt] = handler;
 }
 
 void pic_remap()
 {
-    outb(0x20, 0x11);
-    outb(0xA0, 0x11);
-    outb(0x21, 0x20);
-    outb(0xA1, 0x28);
-    outb(0x21, 0x04);
-    outb(0xA1, 0x02);
-    outb(0x21, 0x01);
-    outb(0xA1, 0x01);
-    outb(0x21, 0x0);
-    outb(0xA1, 0x0);
+	outb(0x20, 0x11);
+	outb(0xA0, 0x11);
+	outb(0x21, 0x20);
+	outb(0xA1, 0x28);
+	outb(0x21, 0x04);
+	outb(0xA1, 0x02);
+	outb(0x21, 0x01);
+	outb(0xA1, 0x01);
+	outb(0x21, 0x0);
+	outb(0xA1, 0x0);
 
 	return;
 }
diff --git a/src/pic.h b/src/pic.h
index a8b6d99..de11f3f 100644
--- a/src/pic.h
+++ b/src/pic.h
@@ -15,6 +15,6 @@
 #define IRQ_TO_INT(irq) ((irq) + 32)
 
 void pic_send_eoi(uchar interrupt);
-void add_interrupt_handler(uchar interrupt, void (* handler)(struct registers));
+void add_interrupt_handler(uchar interrupt, void (*handler)(struct registers *));
 
 void pic_remap();
diff --git a/src/srcmap.txt b/src/srcmap.txt
new file mode 100644
index 0000000..c9219a7
--- /dev/null
+++ b/src/srcmap.txt
@@ -0,0 +1,17 @@
++------------+
+| Source map |
++------------+
+
+
+Source File          Description
+----------------------------------------------------------------
+io.c                 low level memory management stuff, io utils
+log.c                logging, panics, assert, etc
+vga.c                vga drivers
+timer.c              sets up interrupt timer
+descriptor_tables.c  sets up IDT and GDT
+paging.c             sets up paging
+pic.c                IRQ handler
+interrupts.c         ISR handler
+boot.s               calls kmain
+main.c               entry point
diff --git a/src/stdarg.h b/src/stdarg.h
index 3af5dbb..ce9bbc4 100644
--- a/src/stdarg.h
+++ b/src/stdarg.h
@@ -44,14 +44,14 @@
    if this invocation was from the user program.  */
 #ifdef _STDARG_H
 
-#define va_start(v,l)	__builtin_va_start(v,l)
-#define va_end(v)	__builtin_va_end(v)
-#define va_arg(v,l)	__builtin_va_arg(v,l)
-#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
-    || __cplusplus + 0 >= 201103L
-#define va_copy(d,s)	__builtin_va_copy(d,s)
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L ||            \
+	__cplusplus + 0 >= 201103L
+#define va_copy(d, s) __builtin_va_copy(d, s)
 #endif
-#define __va_copy(d,s)	__builtin_va_copy(d,s)
+#define __va_copy(d, s) __builtin_va_copy(d, s)
 
 /* Define va_list, if desired, from __gnuc_va_list. */
 /* We deliberately do not define va_list when called from
@@ -81,13 +81,15 @@
 #define __VA_LIST
 #endif
 #endif /* _VA_LIST_ */
-#else /* not __svr4__ || _SCO_DS */
+#else  /* not __svr4__ || _SCO_DS */
 
 /* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
    But on BSD NET2 we must not test or define or undef it.
    (Note that the comments in NET 2's ansi.h
    are incorrect for _VA_LIST_--see stdio.h!)  */
-#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
+#if !defined(_VA_LIST_) || defined(__BSD_NET2__) || defined(____386BSD____) || \
+	defined(__bsdi__) || defined(__sequent__) || defined(__FreeBSD__) ||       \
+	defined(WINNT)
 /* The macro _VA_LIST_DEFINED is used in Windows NT 3.5  */
 #ifndef _VA_LIST_DEFINED
 /* The macro _VA_LIST is used in SCO Unix 3.2.  */
@@ -101,7 +103,8 @@
 #endif /* not _VA_LIST_T_H */
 #endif /* not _VA_LIST */
 #endif /* not _VA_LIST_DEFINED */
-#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
+#if !(defined(__BSD_NET2__) || defined(____386BSD____) || defined(__bsdi__) || \
+	  defined(__sequent__) || defined(__FreeBSD__))
 #define _VA_LIST_
 #endif
 #ifndef _VA_LIST
diff --git a/src/switch_table.s b/src/switch_table.s
new file mode 100644
index 0000000..d04629b
--- /dev/null
+++ b/src/switch_table.s
@@ -0,0 +1,25 @@
+	[section .text]
+	[bits 32]
+
+;;; TODO: remove useless frame pointer stuff
+	
+	[global load_page_directory]
+load_page_directory:
+	push ebp 					; Save frame pointer
+	mov ebp, esp
+	mov eax, [esp + 8]			; Pointer to directory
+	mov cr3, eax
+	mov esp, ebp
+	pop ebp
+	ret
+
+	[global enable_paging]
+enable_paging:
+	push ebp
+	mov ebp, esp
+	mov eax, cr0
+	or eax, 0x80000000
+	mov cr0, eax
+	mov esp, ebp
+	pop ebp
+	ret
diff --git a/src/timer.c b/src/timer.c
index 72ff1c6..4227949 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -1,14 +1,15 @@
 #include "timer.h"
-#include "pic.h"
-#include "log.h"
-#include "registers.h"
 #include "io.h"
+#include "log.h"
+#include "pic.h"
+#include "registers.h"
 
 static ulong tick = 0;
 
 static void timer_cb(struct registers regs)
 {
-	kprintf("Timer tick %d\n", tick++);
+	if (++tick % 100 == 0)
+		kprintf("Timer tick %d\n", tick);
 }
 
 void init_timer(uint hz)
@@ -21,8 +22,7 @@
 
 	outb(0x43, 0x36);
 	io_wait();
-	uchar l = divisor & 0xff,
-		h = (divisor >> 8) & 0xff;
+	uchar l = divisor & 0xff, h = (divisor >> 8) & 0xff;
 
 	outb(0x40, l);
 	io_wait();
diff --git a/src/vga.c b/src/vga.c
index 06fe608..b6edbb0 100644
--- a/src/vga.c
+++ b/src/vga.c
@@ -51,7 +51,7 @@
 			cursor_x--;
 		break;
 	case '\t':
-		cursor_x = (cursor_x + 8) & ~ 7;
+		cursor_x = (cursor_x + 8) & ~7;
 		break;
 	case '\n':
 		cursor_y++;
@@ -97,8 +97,7 @@
 	{
 		str[i++] = (d % 10) + '0';
 		d /= 10;
-	}
-	while (d > 0 && i < 48); // should never be more than 48 digits anyway
+	} while (d > 0 && i < 48); // should never be more than 48 digits anyway
 
 	for (uint j = i; j; j--)
 	{
@@ -108,9 +107,9 @@
 
 static bool vga_put_nibble(uchar n, bool first)
 {
-	if (first && n == 0)
-		return true;
-	
+//	if (first && n == 0)
+//		return true;
+
 	if (n <= 9)
 		vga_put('0' + n);
 	else
@@ -121,13 +120,13 @@
 
 void vga_putx(uint x)
 {
-	bool first = true;
+	bool first = false;
 
-	for (uint mask = 0xFF000000, shift = 24; mask; mask >>= 8, shift -= 8)
+	for (int shift = 24; shift >= 0; shift -= 8)
 	{
-		uchar byte = (x & mask) >> shift;
+		uchar byte = x >> shift;
 
-		first = vga_put_nibble((byte & 0xf0) >> 8, first);
+		first = vga_put_nibble((byte & 0xf0) >> 4, first);
 		first = vga_put_nibble(byte & 0x0f, first);
 	}
 }