BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / proc

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/proc/apic.c b/proc/apic.c
new file mode 100644
index 0000000..a784f50
--- /dev/null
+++ b/proc/apic.c
@@ -0,0 +1,258 @@
+/*
+ * This file contains code dealing with the Advanced Programmable Interrupt
+ * Controller system.  It should proved a drop-in replacement for the standard
+ * PIC system, abstracting it in the same way.  It should also be able to handle
+ * a non-SMP system, and fall back on the PIC.
+ */
+
+#include <stdint.h>
+#include "proc.h"
+#include "../mem/heap.h"
+#include "../mem/mem.h"
+#include "../task/task.h"
+#include "../io.h"
+#include "../screen.h"
+#include "../spinlock.h"
+
+/* RSDP Descriptor */
+typedef struct RSDPDescriptor {
+	char signature[8];
+	uint8_t checksum;
+	char oem[6];
+	uint8_t revision;
+	uint32_t rsdt;
+} __attribute__((packed)) RSDPDescriptor;
+
+/* System Descriptor Table Header */
+typedef struct SDTHeader {
+	char signature[4];
+	uint32_t length;
+	uint8_t revision;
+	uint8_t checksum;
+	char oem[6];
+	char oemTable[8];
+	uint32_t oemRevision;
+	uint32_t creator;
+	uint32_t creatorRevision;
+} SDTHeader;
+
+/* IOAPIC Interrupt Source Override */
+typedef struct IOAPICOverride {
+	uint8_t type, length;
+	uint8_t bus, irq;
+	uint8_t gsi, flags;
+} IOAPICOverride;
+
+void cpu_load(void);
+extern void ap_trampoline(void);
+
+uint8_t numCores;
+uint8_t bspId;
+uint32_t lapicPtr, ioapicPtr;
+uint8_t lapicIds[MAX_CPUS], lapicNums[MAX_CPUS];
+Spinlock timerLock;
+
+/* Enable APIC */
+static void
+enable_apic(void)
+{
+	LAPIC(0xF0) = 0x1FF;
+	LAPIC(0x80) = 0;
+}
+
+/* Read from the IOAPIC */
+static uint32_t
+read_io_apic(uint32_t reg)
+{
+	uint32_t volatile *ioapic = (uint32_t volatile *) ioapicPtr;
+	ioapic[0] = (reg & 0xFF);
+	return ioapic[4];
+}
+
+/* Write to the IOAPIC */
+static void
+write_io_apic(uint32_t reg, uint32_t value)
+{
+	uint32_t volatile *ioapic = (uint32_t volatile *) ioapicPtr;
+	ioapic[0] = (reg & 0xFF);
+	ioapic[4] = value;
+}
+
+/* Delay in gaps of 100 microseconds */
+static void
+delay(uint32_t time)
+{
+	float calc = (1193182 / 10000) * time;
+	uint32_t divisor = (uint32_t) calc;
+	outb(0x43, 0x30);
+	outb(0x40, divisor & 0xFF);
+	outb(0x40, (divisor >> 8) & 0xFF);
+	do outb(0x43, 0xE2); while (!(inb(0x40) & (1 << 7)));
+}
+
+/* Start the APIC timer */
+static void
+apic_start_timer(void)
+{
+	/* Don't run while another timer is calibrating */
+	acquire(&timerLock);
+
+	/* Start LAPIC countdown from -1 */
+	LAPIC(0x3E0) = 3;
+	LAPIC(0x380) = 0xFFFFFFFF;
+	delay(10);
+
+	/* Stop after PIT fires, count LAPIC ticks */
+	LAPIC(0x320) = 0x10000;
+	uint32_t ticks = 0xFFFFFFFF - LAPIC(0x390);
+
+	/* Tick every 1ms */
+	LAPIC(0x320) = 0x20000 | 32;
+	LAPIC(0x3E0) = 3;
+	LAPIC(0x380) = ticks;
+
+	release(&timerLock);
+}
+
+/* Initialise SMP (RSDT method) */
+void
+init_multicore(void *ebda)
+{
+	numCores = 1;
+	memset(lapicIds, 0, MAX_CPUS);
+	memset(lapicNums, 0, MAX_CPUS);
+
+	init_lock(&timerLock);
+
+	/* Search for SMP tables, start from EBDA start */
+	char *signature = (char *) ebda;
+	uint8_t found;
+	while (signature < (char *) 0x100000) {
+		/* RSDT */
+		if (!memcmp(signature, "RSD PTR ", 8)) {
+			found = 1;
+			break;
+		}
+		signature++;
+	}
+	/* Fall back to PIC */
+	if (!found)
+		return;
+	/* RSDT checksum */
+	uint32_t check = 0, i, j;
+	for (i = 0; i < sizeof(RSDPDescriptor); i++)
+		check += signature[i];
+	if (check % 0x100)
+		return;
+
+	uint8_t *ptr, *ptr2;
+	uint8_t *rsdt, len;
+	uint8_t overrides[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+	IOAPICOverride *iso;
+
+	/* Find APIC table */
+	kprintf("Searching for APIC table");
+	asm volatile("mov $1, %%eax; cpuid; shrl $24, %%ebx" : "=b" (bspId));
+	numCores = 0;
+	rsdt = (uint8_t *) ((RSDPDescriptor *) signature)->rsdt;
+	len = *((uint32_t *) (rsdt + 4));
+	for (ptr2 = rsdt + 36; ptr2 < rsdt + len; ptr2 += 4) {
+		ptr = *((uint8_t **) ptr2);
+		if (!memcmp(ptr, "APIC", 4))
+			break;
+	}
+	if (memcmp(ptr, "APIC", 4))
+		return;
+
+	/* Read APIC table */
+	lapicPtr = *((uint32_t *) (ptr + 0x24));
+	ptr2 = ptr + *((uint32_t *) (ptr + 4));
+	for (ptr += 44; ptr < ptr2; ptr += ptr[1]) {
+		/* Entries */
+		switch (ptr[0]) {
+		case 0: /* Processor Local APIC */
+			if (numCores >= MAX_CPUS)
+				continue;
+			if (ptr[4] & 1) {
+				lapicNums[ptr[3]] = numCores;
+				lapicIds[numCores] = ptr[3];
+				numCores++;
+			}
+			break;
+		case 1: /* IOAPIC */
+			ioapicPtr = *((uint32_t *) (ptr + 4));
+			break;
+		case 2: /* IOAPIC ISO */
+			iso = (void *) ptr;
+			overrides[iso->irq] = iso->gsi;
+			kprintf("  IRQ#%.2d -> GSI#%.2d",
+			        iso->irq, iso->gsi);
+			break;
+		}
+	}
+
+	/* Send INT#1 to IRQ#33 on CPU#0 */
+	write_io_apic(0x10 + (2 * overrides[1] + 0), 33);
+	write_io_apic(0x10 + (2 * overrides[1] + 1), bspId);
+
+	kprintf("Detected %d CPU%c", numCores, (numCores>1)?'s':'\0');
+
+	/* Initialise APs */
+	uintptr_t apTrampoline = 0x2000;
+	memcpy((void *) apTrampoline, &ap_trampoline, 0x1000);
+	for (i = 0; i < numCores; i++) {
+		if (lapicIds[i] == bspId)
+			continue;
+		/* Give each CPU a separate stack */
+		*((uint32_t *) (apTrampoline + 0xFF0)) = 0x7A000 - (i * 0x2000);
+		/* Send INIT IPI */
+		LAPIC(0x280) = 0;
+		LAPIC(0x310) = (LAPIC(0x310) & 0x00FFFFFF)
+		             | (lapicIds[i] << 24);
+		LAPIC(0x300) = (LAPIC(0x300) & 0xFFF00000)
+		             | 0xC500;
+		do {
+			asm("pause" ::: "memory");
+		} while (LAPIC(0x300) & (1 << 12));
+		LAPIC(0x310) = (LAPIC(0x310) & 0x00FFFFFF)
+		             | (lapicIds[i] << 24);
+		LAPIC(0x300) = (LAPIC(0x300) & 0xFFF00000)
+		             | 0x8500;
+		do {
+			asm("pause" ::: "memory");
+		} while (LAPIC(0x300) & (1 << 12));
+		delay(100);
+		/* Send STARTUP IPI (twice) */
+		for (j = 0; j < 2; j++) {
+			LAPIC(0x280) = 0;
+			LAPIC(0x310) = (LAPIC(0x310) & 0x00FFFFFF)
+			             | (lapicIds[i] << 24);
+			LAPIC(0x300) = (LAPIC(0x300) & 0xFFF0F800)
+			             | (0x0600 + ((apTrampoline >> 12) & 0xFF));
+			delay(2);
+			do {
+				asm("pause" ::: "memory");
+			} while (LAPIC(0x300) & (1 << 12));
+		}
+	}
+
+	/* Enable APIC */
+	enable_apic();
+	/* Disable PIC */
+	outb(0x21, 0xFF);
+	outb(0xA1, 0xFF);
+
+	apic_start_timer();
+}
+
+/* AP initialisation routine */
+void
+ap_startup(void)
+{
+//	enable_apic();
+	cpu_load();
+//	apic_start_timer();
+	current = NULL;
+	kprintf("CPU#%d idling", CPUID);
+	while (1) asm volatile("hlt");
+}
diff --git a/proc/gdt.c b/proc/gdt.c
new file mode 100644
index 0000000..6d9a7c7
--- /dev/null
+++ b/proc/gdt.c
@@ -0,0 +1,104 @@
+/*
+ * This file deals with the Global Descriptor Table.  It creates a simple GDT,
+ * suitable for use in the Kernel, and attaches a TSS to the end.  The TSS,
+ * which can be used to switch from ring 3 to ring 0, allows processes access to
+ * all IO ports.
+ */
+
+#include <stdint.h>
+#include "../mem/heap.h"
+#include "../mem/mem.h"
+#include "../mem/frame.h"
+#include "../proc/proc.h"
+#include "../screen.h"
+
+#define GDT_ENTRIES 6
+
+/* Structure for GDT entry */
+static struct GDTEntry {
+	uint16_t limitLower, baseLower;
+	uint8_t baseMiddle, access, gran, baseHigher;
+} __attribute__((packed)) *GDT;
+
+/* Structure for TSS entry */
+static struct TSSEntry {
+	uint32_t prevTSS;
+	uint32_t esp0, ss0;
+	uint32_t esp1, ss1;
+	uint32_t esp2, ss2;
+	uint32_t cr3, eip, eflags;
+	uint32_t eax, ecx, edx, ebx;
+	uint32_t esp, ebp, esi, edi;
+	uint32_t es, cs, ss, ds, fs, gs;
+	uint32_t ldt;
+	uint16_t trap, iomapBase;
+//	uint32_t iomap[2048];
+} __attribute__((packed)) *TSS; /* Per CPU */
+
+void load_gdt(uint32_t gdtPtr);
+void load_tss(void);
+
+/* Set a gate of the GDT */
+static void
+gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit,
+             uint8_t access, uint8_t gran)
+{
+	GDT[num].baseLower = (base & 0xFFFF);
+	GDT[num].baseMiddle = (base >> 16) & 0xFF;
+	GDT[num].baseHigher = (base >> 24) & 0xFF;
+	GDT[num].limitLower = (limit & 0xFFFF);
+	GDT[num].gran = (limit >> 16) & 0x0F;
+	GDT[num].gran |= gran & 0xF0;
+	GDT[num].access = access;
+}
+
+/* Create a TSS */
+static void
+write_tss(uint8_t num, uint32_t esp)
+{
+	uint32_t base = (uint32_t) TSS;
+	uint32_t limit = sizeof(struct TSSEntry) - 1;
+
+	gdt_set_gate(num, base, limit, 0xE9, 0x00);
+	num -= 5;
+	memset(&TSS[num], 0, sizeof(struct TSSEntry));
+	TSS[num].ss0 = 0x10;
+	TSS[num].esp0 = esp;
+	TSS[num].cs = 0x08 | 0;
+	TSS[num].ds = TSS[num].es = TSS[num].ss = 0x10 | 0;
+	TSS[num].fs = TSS[num].gs = 0x10 | 3;
+	TSS[num].iomapBase = 104;
+}
+
+/* Initialise the Kernel GDT */
+void
+init_gdt(void)
+{
+	GDT = (void *) alloc_frames(1);
+	TSS = (void *) (GDT + GDT_ENTRIES);
+	kprintf("Loaded GDT @ %#.8x, TSS @ %#.8x", GDT, TSS);
+}
+
+/* Load the Kernel GDT */
+void
+cpu_load_gdt(void)
+{
+	memset(GDT, 0, sizeof(GDT[0]) * GDT_ENTRIES);
+
+	gdt_set_gate(0, 0x00000000, 0x00000000, 0x00, 0x00); /* Null segment */
+	/* Ring 0 */
+	gdt_set_gate(1, 0x00000000, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
+	gdt_set_gate(2, 0x00000000, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
+	/* Ring 3 */
+	gdt_set_gate(3, 0x00000000, 0xFFFFFFFF, 0xFA, 0xCF); /* Code segment */
+	gdt_set_gate(4, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF); /* Data segment */
+	/* TSS */
+	write_tss(5, 0xF0800000 - sizeof(uintptr_t));
+
+	uint16_t gdtPtr[3];
+	gdtPtr[0] = (sizeof(GDT[0]) * GDT_ENTRIES) - 1;
+	gdtPtr[1] = ((uint32_t) GDT) & 0xFFFF;
+	gdtPtr[2] = ((uint32_t) GDT) >> 16;
+	load_gdt((uint32_t) &gdtPtr);
+	load_tss();
+}
diff --git a/proc/idt.c b/proc/idt.c
new file mode 100644
index 0000000..a1552c2
--- /dev/null
+++ b/proc/idt.c
@@ -0,0 +1,148 @@
+/*
+ * This file deals with the Interrupt Descriptor Table.  It creates a simple
+ * IDT, with hard-coded handler functions.  It is these handler functions that
+ * can run custom handlers, registered at runtime.  This file does not deal with
+ * dispatching messages/signals to processes on an interrupt.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "proc.h"
+#include "../mem/heap.h"
+#include "../mem/frame.h"
+#include "../screen.h"
+
+/* Structure for IDT entry */
+static struct IDTEntry {
+	uint16_t offsetLower, selector;
+	uint8_t zero, typeAttr;
+	uint16_t offsetHigher;
+} __attribute__((packed)) *IDT;
+
+void load_idt(uint32_t ptr[2]);
+/* Exceptions */
+void exc0(void);
+void exc1(void);
+void exc2(void);
+void exc3(void);
+void exc4(void);
+void exc5(void);
+void exc6(void);
+void exc7(void);
+void exc8(void);
+void exc9(void);
+void exc10(void);
+void exc11(void);
+void exc12(void);
+void exc13(void);
+void exc14(void);
+void exc15(void);
+void exc16(void);
+void exc17(void);
+void exc18(void);
+void exc19(void);
+void exc20(void);
+void exc30(void);
+void exc128(void); /* syscall */
+/* Interrutps */
+void irq0(void);
+void irq1(void);
+void irq2(void);
+void irq3(void);
+void irq4(void);
+void irq5(void);
+void irq6(void);
+void irq7(void);
+void irq8(void);
+void irq9(void);
+void irq10(void);
+void irq11(void);
+void irq12(void);
+void irq13(void);
+void irq14(void);
+void irq15(void);
+
+extern void (**exceptions)(InterruptFrame *);
+extern void (**interrupts)(InterruptFrame *);
+
+/* Install an IDT entry */
+static void
+install_idt_entry(uint8_t num, uint32_t addr)
+{
+	IDT[num].offsetLower = addr & 0xFFFF;
+	IDT[num].selector = 0x08;
+	IDT[num].zero = 0;
+	IDT[num].typeAttr = 0x8E | 0x60; /* Allowed from ring 3 */
+	IDT[num].offsetHigher = addr >> 16;
+}
+
+/* Initialise the IDT */
+void
+init_idt(void)
+{
+	IDT = (void *) alloc_frames(1);
+
+	/* Install exceptions */
+	install_idt_entry(0, (uint32_t) exc0);
+	install_idt_entry(1, (uint32_t) exc1);
+	install_idt_entry(2, (uint32_t) exc2);
+	install_idt_entry(3, (uint32_t) exc3);
+	install_idt_entry(4, (uint32_t) exc4);
+	install_idt_entry(5, (uint32_t) exc5);
+	install_idt_entry(6, (uint32_t) exc6);
+	install_idt_entry(7, (uint32_t) exc7);
+	install_idt_entry(8, (uint32_t) exc8);
+	install_idt_entry(9, (uint32_t) exc9);
+	install_idt_entry(10, (uint32_t) exc10);
+	install_idt_entry(11, (uint32_t) exc11);
+	install_idt_entry(12, (uint32_t) exc12);
+	install_idt_entry(13, (uint32_t) exc13);
+	install_idt_entry(14, (uint32_t) exc14);
+	install_idt_entry(15, (uint32_t) exc15);
+	install_idt_entry(16, (uint32_t) exc16);
+	install_idt_entry(17, (uint32_t) exc17);
+	install_idt_entry(18, (uint32_t) exc18);
+	install_idt_entry(19, (uint32_t) exc19);
+	install_idt_entry(20, (uint32_t) exc20);
+	install_idt_entry(30, (uint32_t) exc30);
+
+	/* Install interrutps */
+	install_idt_entry(32, (uint32_t) irq0);
+	install_idt_entry(33, (uint32_t) irq1);
+	install_idt_entry(34, (uint32_t) irq2);
+	install_idt_entry(35, (uint32_t) irq3);
+	install_idt_entry(36, (uint32_t) irq4);
+	install_idt_entry(37, (uint32_t) irq5);
+	install_idt_entry(38, (uint32_t) irq6);
+	install_idt_entry(39, (uint32_t) irq7);
+	install_idt_entry(40, (uint32_t) irq8);
+	install_idt_entry(41, (uint32_t) irq9);
+	install_idt_entry(42, (uint32_t) irq10);
+	install_idt_entry(43, (uint32_t) irq11);
+	install_idt_entry(44, (uint32_t) irq12);
+	install_idt_entry(45, (uint32_t) irq13);
+	install_idt_entry(46, (uint32_t) irq14);
+	install_idt_entry(47, (uint32_t) irq15);
+
+	/* Install syscall handler */
+	install_idt_entry(128, (uint32_t) exc128);
+
+	exceptions = (void (**)(InterruptFrame *)) (IDT + 256);
+	interrupts = (void (**)(InterruptFrame *)) (exceptions + 32);
+	memset(exceptions, 0, 1024);
+
+	kprintf("Loaded IDT @ %#.8x, Exceptions @ %#.8x, Interrupts @ %#.8x",
+	        IDT, exceptions, interrupts);
+}
+
+/* Load the IDT */
+void
+cpu_load_idt(void)
+{
+	uint32_t idtAddr, idtPtr[2];
+	idtAddr = (uint32_t) IDT;
+	idtPtr[0] = sizeof(struct IDTEntry) * 256;
+	idtPtr[0] += (idtAddr & 0xFFFF) << 16;
+	idtPtr[1] = idtAddr >> 16;
+	load_idt(idtPtr);
+}
diff --git a/proc/irqs.c b/proc/irqs.c
new file mode 100644
index 0000000..f9a523c
--- /dev/null
+++ b/proc/irqs.c
@@ -0,0 +1,80 @@
+/*
+ * This file contains the abstraction for exceptions and interrupts.  It
+ * presents a system of registrable exception/interrupt handlers.  It also
+ * contains the generic handlers, which pass control to the appropriate
+ * registered handler.  This file does not deal with dispatching
+ * messages/signals to processes on an interrupt.
+ */
+
+#include <stdint.h>
+#include "proc.h"
+#include "../proc/proc.h"
+#include "../task/task.h"
+#include "../io.h"
+#include "../screen.h"
+
+void (**exceptions)(InterruptFrame *);
+void (**interrupts)(InterruptFrame *);
+
+/* Register an exception handler */
+void
+register_exception(int num, void (*addr)(InterruptFrame *))
+{
+	if (num >= 0 && num < 32)
+		exceptions[num] = addr;
+}
+
+/* Register an interrupt handler */
+void
+register_interrupt(int num, void (*addr)(InterruptFrame *))
+{
+	if (num >= 0 && num < 224)
+		interrupts[num] = addr;
+}
+
+/* Call the appropriate exception handler */
+uintptr_t
+exc_handler(InterruptFrame frame)
+{
+	uint8_t num = frame.intNo & 0xFF;
+
+	/* System Call */
+	if (num == 0x80)
+		syscall_handler(&frame);
+	/* Other exception */
+	else if (exceptions[num])
+		exceptions[num](&frame);
+	else
+		panic("Unhandled exception %d (%#x) @ %#.8x [CPU#%d]\n"
+		      "EFLAGS: %#.8x",
+		      num, frame.errCode, frame.eip, CPUID, frame.eflags);
+
+	/* Send EOI */
+	LAPIC(0xB0) = 0;
+
+	if (current)
+		if (current->tls)
+			return current->tls->start + 4;
+	return 0;
+}
+
+/* Call the appropriate interrupt handler */
+uintptr_t
+irq_handler(InterruptFrame frame)
+{
+	uint8_t num = (frame.intNo & 0xFF) - 32;
+
+	if (interrupts[num])
+		interrupts[num](&frame);
+
+	/* Send EOI */
+	outb(0x20, 0x20);
+	if (num >= 8)
+		outb(0xA0, 0x20);
+	LAPIC(0xB0) = 0;
+
+	if (current)
+		if (current->tls)
+			return current->tls->start + 4;
+	return 0;
+}
diff --git a/proc/load.S b/proc/load.S
new file mode 100644
index 0000000..98330a0
--- /dev/null
+++ b/proc/load.S
@@ -0,0 +1,38 @@
+; This file is responsible for loading the tables onto the CPU.  The functions
+; will load the GDT, IDT and TSS onto the CPU running the function.  They only
+; provide a wrapper for the relevant x86 instruction, and do not do any table
+; creation.  See the relevant C files for the table setup routines.  The GDT and
+; IDT require a pointer to the table, while the TSS can be loaded from the
+; currently loaded GDT.
+
+[bits 32]
+
+; Load the IDT
+[global load_idt]
+load_idt:
+	mov eax, [esp + 4]
+	lidt [eax]
+	ret
+
+; Load the GDT
+[global load_gdt]
+load_gdt:
+	mov eax, [esp + 4]
+	lgdt [eax]
+
+	mov ax, 0x10
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+	mov ss, ax
+	jmp 0x08:.flush
+.flush:
+	ret
+
+; Load the TSS
+[global load_tss]
+load_tss:
+	mov ax, 0x28 | 3
+	ltr ax
+	ret
diff --git a/proc/pic.c b/proc/pic.c
new file mode 100644
index 0000000..e478921
--- /dev/null
+++ b/proc/pic.c
@@ -0,0 +1,40 @@
+/*
+ * This file deals with the Programmable Interrupt Controller.  It is usually
+ * disable and replaced by the APIC.
+ */
+
+#include "../io.h"
+
+/* Initialise the PIC to a specified frequency */
+static void
+init_pit(void)
+{
+	uint32_t divisor = 1193182 / 1000;
+	outb(0x43, 0x36);
+	outb(0x40, divisor & 0xFF);
+	outb(0x40, (divisor >> 8) & 0xFF);
+}
+
+/* Initialise the PIC */
+void
+init_pic(void)
+{
+	/*
+	 * By default interrupts and exceptions both start at IRQ#0.  To avoid
+	 * collision we can map interrupts to start at IRQ#32.  Since lower
+	 * numbered IRQ lines are higher priority, exceptions have priority.
+	 */
+	outb(0x20, 0x11); io_wait();
+	outb(0xA0, 0x11); io_wait();
+	outb(0x21, 0x20); io_wait();
+	outb(0xA1, 0x28); io_wait();
+	outb(0x21, 0x04); io_wait();
+	outb(0xA1, 0x02); io_wait();
+	outb(0x21, 0x01); io_wait();
+	outb(0xA1, 0x01); io_wait();
+	outb(0x21, 0x00); io_wait();
+	outb(0xA1, 0x00); io_wait();
+
+	init_pit();
+}
+
diff --git a/proc/proc.h b/proc/proc.h
new file mode 100644
index 0000000..bba44cf
--- /dev/null
+++ b/proc/proc.h
@@ -0,0 +1,32 @@
+#ifndef KERNEL_PROC_H
+#define KERNEL_PROC_H
+
+#include <stdint.h>
+
+/* Structure pushed on interrupt */
+typedef struct InterruptFrame {
+	uint32_t ds, fs, gs;
+	uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
+	uint32_t intNo, errCode;
+	uint32_t eip, cs, eflags, useresp, ss;
+} InterruptFrame;
+
+extern uint8_t numCores;
+extern uint32_t lapicPtr, ioapicPtr;
+extern uint8_t lapicNums[];
+#define LAPIC(off)  (*((uint32_t *) ((uint32_t)  lapicPtr + (off))))
+#define IOAPIC(off) (*((uint32_t *) ((uint32_t) ioapicPtr + (off))))
+#define CPUID lapicNums[(uint8_t) (LAPIC(0x20) >> 24)]
+#define MAX_CPUS 2
+
+void init_pic(void);
+void init_multicore(void *ebda);
+
+void init_idt(void);
+void init_gdt(void);
+void cpu_load_idt(void);
+void cpu_load_gdt(void);
+void register_exception(int num, void (*handler)(InterruptFrame *));
+void register_interrupt(int num, void (*handler)(InterruptFrame *));
+
+#endif
diff --git a/proc/stub.S b/proc/stub.S
new file mode 100644
index 0000000..a16d014
--- /dev/null
+++ b/proc/stub.S
@@ -0,0 +1,149 @@
+; This file contains the stubs for the interrupt handlers, which can push more
+; useful information on the the stack, before calling a generic handler.  Since
+; each exception/interrupt must have it's own handler, macros are used to create
+; a handler for each of them.
+
+[bits 32]
+
+[extern irq_handler]
+[extern exc_handler]
+
+; Exception without error code
+%macro EXC_NOERRCODE 1
+[global exc%1]
+exc%1:
+	cli
+	push byte 0
+	push %1
+	jmp exc_stub
+%endmacro
+
+; Exception with error code
+%macro EXC_ERRCODE 1
+[global exc%1]
+exc%1:
+	cli
+	push %1
+	jmp exc_stub
+%endmacro
+
+; Interrupt
+%macro IRQ 2
+[global irq%1]
+irq%1:
+	cli
+	push byte 0
+	push byte %2
+	jmp irq_stub
+%endmacro
+
+EXC_NOERRCODE 0
+EXC_NOERRCODE 1
+EXC_NOERRCODE 2
+EXC_NOERRCODE 3
+EXC_NOERRCODE 4
+EXC_NOERRCODE 5
+EXC_NOERRCODE 6
+EXC_NOERRCODE 7
+EXC_ERRCODE   8
+EXC_NOERRCODE 9
+EXC_ERRCODE   10
+EXC_ERRCODE   11
+EXC_ERRCODE   12
+EXC_ERRCODE   13
+EXC_ERRCODE   14
+EXC_NOERRCODE 15
+EXC_NOERRCODE 16
+EXC_ERRCODE   17
+EXC_NOERRCODE 18
+EXC_NOERRCODE 19
+EXC_NOERRCODE 20
+EXC_NOERRCODE 30
+EXC_NOERRCODE 128 ; syscall
+
+IRQ  0, 32
+IRQ  1, 33
+IRQ  2, 34
+IRQ  3, 35
+IRQ  4, 36
+IRQ  5, 37
+IRQ  6, 38
+IRQ  7, 39
+IRQ  8, 40
+IRQ  9, 41
+IRQ 10, 42
+IRQ 11, 43
+IRQ 12, 44
+IRQ 13, 45
+IRQ 14, 46
+IRQ 15, 47
+
+; Handle an exception
+exc_stub:
+	pusha
+	mov ax, gs
+	push eax
+	mov ax, fs
+	push eax
+	mov ax, ds
+	push eax
+
+	mov ax, 0x10
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+
+	call exc_handler
+
+	pop ebx
+	mov ds, bx
+	mov es, bx
+	pop ebx
+	mov fs, bx
+	pop ebx
+	mov gs, bx
+
+	mov ecx, 0xC0000101
+	xor edx, edx
+	wrmsr
+
+	popa
+	add esp, 8
+	sti
+	iret
+
+; Handle an interrupt
+irq_stub:
+	pusha
+	mov ax, gs
+	push eax
+	mov ax, fs
+	push eax
+	mov ax, ds
+	push eax
+
+	mov ax, 0x10
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+
+	call irq_handler
+
+	pop ebx
+	mov ds, bx
+	mov es, bx
+	pop ebx
+	mov fs, bx
+	pop ebx
+	mov gs, bx
+
+	mov ecx, 0xC0000101
+	xor edx, edx
+	wrmsr
+
+	popa
+	add esp, 8
+	sti
+	iret
diff --git a/proc/trampoline.S b/proc/trampoline.S
new file mode 100644
index 0000000..8a8656f
--- /dev/null
+++ b/proc/trampoline.S
@@ -0,0 +1,52 @@
+; This file contains the AP trampoline code to bounce it back into protected
+; mode and run the Kernel on them.  The location of the stack is set by the
+; calling code.  This code runs initially in real (16-bit) mode, at 0x0000 in
+; physical memory.  Modifying this code should be done with care, since it makes
+; use of fixed offsets in memory to jump around.
+
+[bits 16]
+
+[extern ap_startup]
+
+; This is the code run by the APs on startup.  They need to initialise
+; themselves, which includes setting up a GDT and switching to protected mode.
+; When they're in protected mode they can just run their main C function.
+[global ap_trampoline]
+ap_trampoline:
+	cli
+	cld
+	jmp 0x0000:0x2040 ; continue
+
+align 16
+.gdt_start:
+	dd 0, 0
+	dd 0x0000FFFF, 0x00CF9A00 ; Flat Code
+	dd 0x0000FFFF, 0x00CF9200 ; Flat Data
+	dd 0x00000068, 0x00CF8900 ; TSS
+.gdt_desc:
+	dw .gdt_desc - .gdt_start - 1
+	dd 0x2010 ; gdt_start
+	dd 0, 0
+
+align 64
+.continue:
+	xor ax, ax
+	mov ds, ax
+	lgdt [0x2030] ; gdt_desc
+	mov eax, cr0
+	or eax, 0x01
+	mov cr0, eax
+	jmp 0x08:0x2060 ; pm
+
+align 32
+[bits 32]
+.pm:
+	mov ax, 0x10
+	mov ds, ax
+	mov ss, ax
+	; Load passed stack
+	mov eax, [0x2FF0]
+	mov esp, eax
+	mov ebp, esp
+	sti
+	jmp 0x08:ap_startup