From 16b7b4c2c008c976ee5948c97a8337d6224c3be9 Mon Sep 17 00:00:00 2001
From: Freya Murphy <freya@freyacat.org>
Date: Thu, 3 Apr 2025 21:32:00 -0400
Subject: [PATCH] add 64-bit idt/pic and fix paging

---
 build.zig                  |   7 +-
 kernel/cpu/cpu.c           |  10 +
 kernel/cpu/fpu.c           |  12 +
 kernel/cpu/fpu.h           |  14 +
 kernel/cpu/idt.S           | 666 +++++++++++++++++++++++++++++++++++++
 kernel/cpu/idt.c           | 204 ++++++++++++
 kernel/cpu/idt.h           |  68 ++++
 kernel/cpu/pic.c           |  90 +++++
 kernel/cpu/pic.h           |  42 +++
 kernel/include/comus/cpu.h |  17 +
 kernel/io/io.c             |  11 +-
 kernel/kernel.c            |  10 +-
 kernel/kernel.ld           |   8 -
 kernel/memory/paging.c     |   2 +-
 kernel/memory/virtalloc.c  |   2 +-
 15 files changed, 1147 insertions(+), 16 deletions(-)
 create mode 100644 kernel/cpu/cpu.c
 create mode 100644 kernel/cpu/fpu.c
 create mode 100644 kernel/cpu/fpu.h
 create mode 100644 kernel/cpu/idt.S
 create mode 100644 kernel/cpu/idt.c
 create mode 100644 kernel/cpu/idt.h
 create mode 100644 kernel/cpu/pic.c
 create mode 100644 kernel/cpu/pic.h
 create mode 100644 kernel/include/comus/cpu.h

diff --git a/build.zig b/build.zig
index f7e0e87..6ca2ff3 100644
--- a/build.zig
+++ b/build.zig
@@ -24,7 +24,12 @@ const boot_src = &[_][]const u8{"boot/boot.S"};
 
 const kernel_src = &[_][]const u8{
     "kernel/entry.S", // must be first
-    "kernel/kernel.c",
+    "kernel/kernel.c", // main function
+    "kernel/cpu/cpu.c",
+    "kernel/cpu/fpu.c",
+    "kernel/cpu/idt.c",
+    "kernel/cpu/idt.S",
+    "kernel/cpu/pic.c",
     "kernel/io/io.c",
     "kernel/io/panic.c",
     "kernel/memory/memory.c",
diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c
new file mode 100644
index 0000000..8f37402
--- /dev/null
+++ b/kernel/cpu/cpu.c
@@ -0,0 +1,10 @@
+
+#include "fpu.h"
+#include "pic.h"
+#include "idt.h"
+
+void cpu_init(void) {
+	pic_remap();
+	idt_init();
+	fpu_init();
+}
diff --git a/kernel/cpu/fpu.c b/kernel/cpu/fpu.c
new file mode 100644
index 0000000..f2674a7
--- /dev/null
+++ b/kernel/cpu/fpu.c
@@ -0,0 +1,12 @@
+#include <lib.h>
+
+#include "fpu.h"
+
+void fpu_init(void) {
+	size_t cr4;
+	uint16_t cw = 0x37F;
+	__asm__ volatile ("mov %%cr4, %0" : "=r"(cr4));
+	cr4 |= 0x200;
+	__asm__ volatile ("mov %0, %%cr4" :: "r"(cr4));
+	__asm__ volatile("fldcw %0" :: "m"(cw));
+}
diff --git a/kernel/cpu/fpu.h b/kernel/cpu/fpu.h
new file mode 100644
index 0000000..edb4e81
--- /dev/null
+++ b/kernel/cpu/fpu.h
@@ -0,0 +1,14 @@
+/**
+ * @file fpu.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * FPU functions
+ */
+
+#ifndef FPU_H_
+#define FPU_H_
+
+void fpu_init(void);
+
+#endif /* fpu.h */
diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S
new file mode 100644
index 0000000..0ba35f8
--- /dev/null
+++ b/kernel/cpu/idt.S
@@ -0,0 +1,666 @@
+	.global isr_stub_table
+
+	.extern idt_exception_handler
+	.extern idt_pic_timer
+	.extern idt_pic_keyboard
+	.extern idt_pic_mouse
+	.extern idt_pic_eoi
+
+.macro PUSHALL
+	pushq	%rax
+	pushq 	%rbx
+	pushq 	%rcx
+	pushq 	%rdx
+	pushq 	%rsi
+	pushq 	%rdi
+	pushq 	%rbp
+	pushq 	%r8
+	pushq 	%r9
+	pushq 	%r10
+	pushq 	%r11
+	pushq 	%r12
+	pushq 	%r13
+	pushq 	%r14
+	pushq 	%r15
+.endm
+
+.macro POPALL
+	popq	%r15
+	popq 	%r14
+	popq 	%r13
+	popq 	%r12
+	popq 	%r11
+	popq 	%r10
+	popq 	%r9
+	popq 	%r8
+	popq 	%rbp
+	popq 	%rdi
+	popq 	%rsi
+	popq 	%rdx
+	popq 	%rcx
+	popq 	%rbx
+	popq 	%rax
+.endm
+
+# call the exception handler with the interrupt number
+# args: interrupt number
+.macro ISRException num
+	.align 8
+isr_stub_\num:
+	PUSHALL
+	cld
+	movq	$\num, %rdi			# exception number
+	movq	$0, %rsi                # placeholder error code
+	movq	%rsp, %rdx				# top of stack
+	callq	idt_exception_handler
+	POPALL
+	iretq
+.endm
+
+# call the exception handler with the interrupt number
+# these exceptions also put an error code on the stack
+# args: interrupt number
+.macro ISRExceptionCode num
+	.align 8
+isr_stub_\num:
+	# retrieve the error code without corrupting registers
+	mov 	%eax, isr_tmp
+	popq	%rax
+	mov 	%eax, isr_err_code
+	movq	isr_tmp, %rax
+	PUSHALL
+	cld
+	movq	$\num, %rdi             # exception number
+	movq	isr_err_code, %rsi      # error code
+	movq	%rsp, %rdx              # top of stack
+	callq	idt_exception_handler
+	POPALL
+	iretq
+.endm
+
+.macro PICGeneric num
+	.align 8
+isr_stub_\num:
+	PUSHALL
+	cld
+	movq	$\num, %rdi
+	callq	idt_pic_eoi
+	POPALL
+	iretq
+.endm
+
+.macro PICTimer num
+	.align 8
+isr_stub_\num:
+	PUSHALL
+	cld
+	callq	idt_pic_timer
+	movq	$\num, %rdi
+	callq	idt_pic_eoi
+	POPALL
+	iretq
+.endm
+
+.macro PICKeyboard num
+	.align 8
+isr_stub_\num:
+	PUSHALL
+	cld
+	callq	idt_pic_keyboard
+	movq	$\num, %rdi
+	callq	idt_pic_eoi
+	POPALL
+	iretq
+.endm
+
+.macro PICMouse num
+	.align 8
+isr_stub_\num:
+	PUSHALL
+	cld
+	callq	idt_pic_mouse
+	movq	$\num, %rdi
+	callq	idt_pic_eoi
+	POPALL
+	iretq
+.endm
+
+# do nothing
+# args: interrupt number
+.macro ISRIgnore num
+	.align 8
+isr_stub_\num:
+	iretq
+.endm
+
+# isr temp storage
+	.section .data
+isr_tmp:
+	.quad 0
+isr_err_code:
+	.quad 0
+
+# isr stub table
+	.section .rodata
+	.align 16
+	.code64
+isr_stub_table:
+	.quad isr_stub_0
+	.quad isr_stub_1
+	.quad isr_stub_2
+	.quad isr_stub_3
+	.quad isr_stub_4
+	.quad isr_stub_5
+	.quad isr_stub_6
+	.quad isr_stub_7
+	.quad isr_stub_8
+	.quad isr_stub_9
+	.quad isr_stub_10
+	.quad isr_stub_11
+	.quad isr_stub_12
+	.quad isr_stub_13
+	.quad isr_stub_14
+	.quad isr_stub_15
+	.quad isr_stub_16
+	.quad isr_stub_17
+	.quad isr_stub_18
+	.quad isr_stub_19
+	.quad isr_stub_20
+	.quad isr_stub_21
+	.quad isr_stub_22
+	.quad isr_stub_23
+	.quad isr_stub_24
+	.quad isr_stub_25
+	.quad isr_stub_26
+	.quad isr_stub_27
+	.quad isr_stub_28
+	.quad isr_stub_29
+	.quad isr_stub_30
+	.quad isr_stub_31
+	.quad isr_stub_32
+	.quad isr_stub_33
+	.quad isr_stub_34
+	.quad isr_stub_35
+	.quad isr_stub_36
+	.quad isr_stub_37
+	.quad isr_stub_38
+	.quad isr_stub_39
+	.quad isr_stub_40
+	.quad isr_stub_41
+	.quad isr_stub_42
+	.quad isr_stub_43
+	.quad isr_stub_44
+	.quad isr_stub_45
+	.quad isr_stub_46
+	.quad isr_stub_47
+	.quad isr_stub_48
+	.quad isr_stub_49
+	.quad isr_stub_50
+	.quad isr_stub_51
+	.quad isr_stub_52
+	.quad isr_stub_53
+	.quad isr_stub_54
+	.quad isr_stub_55
+	.quad isr_stub_56
+	.quad isr_stub_57
+	.quad isr_stub_58
+	.quad isr_stub_59
+	.quad isr_stub_60
+	.quad isr_stub_61
+	.quad isr_stub_62
+	.quad isr_stub_63
+	.quad isr_stub_64
+	.quad isr_stub_65
+	.quad isr_stub_66
+	.quad isr_stub_67
+	.quad isr_stub_68
+	.quad isr_stub_69
+	.quad isr_stub_70
+	.quad isr_stub_71
+	.quad isr_stub_72
+	.quad isr_stub_73
+	.quad isr_stub_74
+	.quad isr_stub_75
+	.quad isr_stub_76
+	.quad isr_stub_77
+	.quad isr_stub_78
+	.quad isr_stub_79
+	.quad isr_stub_80
+	.quad isr_stub_81
+	.quad isr_stub_82
+	.quad isr_stub_83
+	.quad isr_stub_84
+	.quad isr_stub_85
+	.quad isr_stub_86
+	.quad isr_stub_87
+	.quad isr_stub_88
+	.quad isr_stub_89
+	.quad isr_stub_90
+	.quad isr_stub_91
+	.quad isr_stub_92
+	.quad isr_stub_93
+	.quad isr_stub_94
+	.quad isr_stub_95
+	.quad isr_stub_96
+	.quad isr_stub_97
+	.quad isr_stub_98
+	.quad isr_stub_99
+	.quad isr_stub_100
+	.quad isr_stub_101
+	.quad isr_stub_102
+	.quad isr_stub_103
+	.quad isr_stub_104
+	.quad isr_stub_105
+	.quad isr_stub_106
+	.quad isr_stub_107
+	.quad isr_stub_108
+	.quad isr_stub_109
+	.quad isr_stub_110
+	.quad isr_stub_111
+	.quad isr_stub_112
+	.quad isr_stub_113
+	.quad isr_stub_114
+	.quad isr_stub_115
+	.quad isr_stub_116
+	.quad isr_stub_117
+	.quad isr_stub_118
+	.quad isr_stub_119
+	.quad isr_stub_120
+	.quad isr_stub_121
+	.quad isr_stub_122
+	.quad isr_stub_123
+	.quad isr_stub_124
+	.quad isr_stub_125
+	.quad isr_stub_126
+	.quad isr_stub_127
+	.quad isr_stub_128
+	.quad isr_stub_129
+	.quad isr_stub_130
+	.quad isr_stub_131
+	.quad isr_stub_132
+	.quad isr_stub_133
+	.quad isr_stub_134
+	.quad isr_stub_135
+	.quad isr_stub_136
+	.quad isr_stub_137
+	.quad isr_stub_138
+	.quad isr_stub_139
+	.quad isr_stub_140
+	.quad isr_stub_141
+	.quad isr_stub_142
+	.quad isr_stub_143
+	.quad isr_stub_144
+	.quad isr_stub_145
+	.quad isr_stub_146
+	.quad isr_stub_147
+	.quad isr_stub_148
+	.quad isr_stub_149
+	.quad isr_stub_150
+	.quad isr_stub_151
+	.quad isr_stub_152
+	.quad isr_stub_153
+	.quad isr_stub_154
+	.quad isr_stub_155
+	.quad isr_stub_156
+	.quad isr_stub_157
+	.quad isr_stub_158
+	.quad isr_stub_159
+	.quad isr_stub_160
+	.quad isr_stub_161
+	.quad isr_stub_162
+	.quad isr_stub_163
+	.quad isr_stub_164
+	.quad isr_stub_165
+	.quad isr_stub_166
+	.quad isr_stub_167
+	.quad isr_stub_168
+	.quad isr_stub_169
+	.quad isr_stub_170
+	.quad isr_stub_171
+	.quad isr_stub_172
+	.quad isr_stub_173
+	.quad isr_stub_174
+	.quad isr_stub_175
+	.quad isr_stub_176
+	.quad isr_stub_177
+	.quad isr_stub_178
+	.quad isr_stub_179
+	.quad isr_stub_180
+	.quad isr_stub_181
+	.quad isr_stub_182
+	.quad isr_stub_183
+	.quad isr_stub_184
+	.quad isr_stub_185
+	.quad isr_stub_186
+	.quad isr_stub_187
+	.quad isr_stub_188
+	.quad isr_stub_189
+	.quad isr_stub_190
+	.quad isr_stub_191
+	.quad isr_stub_192
+	.quad isr_stub_193
+	.quad isr_stub_194
+	.quad isr_stub_195
+	.quad isr_stub_196
+	.quad isr_stub_197
+	.quad isr_stub_198
+	.quad isr_stub_199
+	.quad isr_stub_200
+	.quad isr_stub_201
+	.quad isr_stub_202
+	.quad isr_stub_203
+	.quad isr_stub_204
+	.quad isr_stub_205
+	.quad isr_stub_206
+	.quad isr_stub_207
+	.quad isr_stub_208
+	.quad isr_stub_209
+	.quad isr_stub_210
+	.quad isr_stub_211
+	.quad isr_stub_212
+	.quad isr_stub_213
+	.quad isr_stub_214
+	.quad isr_stub_215
+	.quad isr_stub_216
+	.quad isr_stub_217
+	.quad isr_stub_218
+	.quad isr_stub_219
+	.quad isr_stub_220
+	.quad isr_stub_221
+	.quad isr_stub_222
+	.quad isr_stub_223
+	.quad isr_stub_224
+	.quad isr_stub_225
+	.quad isr_stub_226
+	.quad isr_stub_227
+	.quad isr_stub_228
+	.quad isr_stub_229
+	.quad isr_stub_230
+	.quad isr_stub_231
+	.quad isr_stub_232
+	.quad isr_stub_233
+	.quad isr_stub_234
+	.quad isr_stub_235
+	.quad isr_stub_236
+	.quad isr_stub_237
+	.quad isr_stub_238
+	.quad isr_stub_239
+	.quad isr_stub_240
+	.quad isr_stub_241
+	.quad isr_stub_242
+	.quad isr_stub_243
+	.quad isr_stub_244
+	.quad isr_stub_245
+	.quad isr_stub_246
+	.quad isr_stub_247
+	.quad isr_stub_248
+	.quad isr_stub_249
+	.quad isr_stub_250
+	.quad isr_stub_251
+	.quad isr_stub_252
+	.quad isr_stub_253
+	.quad isr_stub_254
+	.quad isr_stub_255
+
+# isr stubs
+	.section .text
+	.code64
+
+ISRException 0
+ISRException 1
+ISRException 2
+ISRException 3
+ISRException 4
+ISRException 5
+ISRException 6
+ISRException 7
+ISRExceptionCode 8
+ISRException 9
+ISRExceptionCode 10
+ISRExceptionCode 11
+ISRExceptionCode 12
+ISRExceptionCode 13
+ISRExceptionCode 14
+ISRException 15
+ISRException 16
+ISRExceptionCode 17
+ISRException 18
+ISRException 19
+ISRException 20
+ISRExceptionCode 21
+ISRException 22
+ISRException 23
+ISRException 24
+ISRException 25
+ISRException 26
+ISRException 27
+ISRException 28
+ISRExceptionCode 29
+ISRExceptionCode 30
+ISRException 31
+
+PICTimer    32 # 0
+PICKeyboard 33 # 1
+PICGeneric  34 # 2
+PICGeneric  35 # 3
+PICGeneric  36 # 4
+PICGeneric  37 # 5
+PICGeneric  38 # 6
+PICGeneric  39 # 7
+PICGeneric  40 # 8
+PICGeneric  41 # 9
+PICGeneric  42 # 10
+PICGeneric  43 # 11
+PICMouse    44 # 12
+PICGeneric  45 # 13
+PICGeneric  46 # 14
+PICGeneric  47 # 15
+
+ISRIgnore 48
+ISRIgnore 49
+ISRIgnore 50
+ISRIgnore 51
+ISRIgnore 52
+ISRIgnore 53
+ISRIgnore 54
+ISRIgnore 55
+ISRIgnore 56
+ISRIgnore 57
+ISRIgnore 58
+ISRIgnore 59
+ISRIgnore 60
+ISRIgnore 61
+ISRIgnore 62
+ISRIgnore 63
+ISRIgnore 64
+ISRIgnore 65
+ISRIgnore 66
+ISRIgnore 67
+ISRIgnore 68
+ISRIgnore 69
+ISRIgnore 70
+ISRIgnore 71
+ISRIgnore 72
+ISRIgnore 73
+ISRIgnore 74
+ISRIgnore 75
+ISRIgnore 76
+ISRIgnore 77
+ISRIgnore 78
+ISRIgnore 79
+ISRIgnore 80
+ISRIgnore 81
+ISRIgnore 82
+ISRIgnore 83
+ISRIgnore 84
+ISRIgnore 85
+ISRIgnore 86
+ISRIgnore 87
+ISRIgnore 88
+ISRIgnore 89
+ISRIgnore 90
+ISRIgnore 91
+ISRIgnore 92
+ISRIgnore 93
+ISRIgnore 94
+ISRIgnore 95
+ISRIgnore 96
+ISRIgnore 97
+ISRIgnore 98
+ISRIgnore 99
+ISRIgnore 100
+ISRIgnore 101
+ISRIgnore 102
+ISRIgnore 103
+ISRIgnore 104
+ISRIgnore 105
+ISRIgnore 106
+ISRIgnore 107
+ISRIgnore 108
+ISRIgnore 109
+ISRIgnore 110
+ISRIgnore 111
+ISRIgnore 112
+ISRIgnore 113
+ISRIgnore 114
+ISRIgnore 115
+ISRIgnore 116
+ISRIgnore 117
+ISRIgnore 118
+ISRIgnore 119
+ISRIgnore 120
+ISRIgnore 121
+ISRIgnore 122
+ISRIgnore 123
+ISRIgnore 124
+ISRIgnore 125
+ISRIgnore 126
+ISRIgnore 127
+ISRIgnore 128
+ISRIgnore 129
+ISRIgnore 130
+ISRIgnore 131
+ISRIgnore 132
+ISRIgnore 133
+ISRIgnore 134
+ISRIgnore 135
+ISRIgnore 136
+ISRIgnore 137
+ISRIgnore 138
+ISRIgnore 139
+ISRIgnore 140
+ISRIgnore 141
+ISRIgnore 142
+ISRIgnore 143
+ISRIgnore 144
+ISRIgnore 145
+ISRIgnore 146
+ISRIgnore 147
+ISRIgnore 148
+ISRIgnore 149
+ISRIgnore 150
+ISRIgnore 151
+ISRIgnore 152
+ISRIgnore 153
+ISRIgnore 154
+ISRIgnore 155
+ISRIgnore 156
+ISRIgnore 157
+ISRIgnore 158
+ISRIgnore 159
+ISRIgnore 160
+ISRIgnore 161
+ISRIgnore 162
+ISRIgnore 163
+ISRIgnore 164
+ISRIgnore 165
+ISRIgnore 166
+ISRIgnore 167
+ISRIgnore 168
+ISRIgnore 169
+ISRIgnore 170
+ISRIgnore 171
+ISRIgnore 172
+ISRIgnore 173
+ISRIgnore 174
+ISRIgnore 175
+ISRIgnore 176
+ISRIgnore 177
+ISRIgnore 178
+ISRIgnore 179
+ISRIgnore 180
+ISRIgnore 181
+ISRIgnore 182
+ISRIgnore 183
+ISRIgnore 184
+ISRIgnore 185
+ISRIgnore 186
+ISRIgnore 187
+ISRIgnore 188
+ISRIgnore 189
+ISRIgnore 190
+ISRIgnore 191
+ISRIgnore 192
+ISRIgnore 193
+ISRIgnore 194
+ISRIgnore 195
+ISRIgnore 196
+ISRIgnore 197
+ISRIgnore 198
+ISRIgnore 199
+ISRIgnore 200
+ISRIgnore 201
+ISRIgnore 202
+ISRIgnore 203
+ISRIgnore 204
+ISRIgnore 205
+ISRIgnore 206
+ISRIgnore 207
+ISRIgnore 208
+ISRIgnore 209
+ISRIgnore 210
+ISRIgnore 211
+ISRIgnore 212
+ISRIgnore 213
+ISRIgnore 214
+ISRIgnore 215
+ISRIgnore 216
+ISRIgnore 217
+ISRIgnore 218
+ISRIgnore 219
+ISRIgnore 220
+ISRIgnore 221
+ISRIgnore 222
+ISRIgnore 223
+ISRIgnore 224
+ISRIgnore 225
+ISRIgnore 226
+ISRIgnore 227
+ISRIgnore 228
+ISRIgnore 229
+ISRIgnore 230
+ISRIgnore 231
+ISRIgnore 232
+ISRIgnore 233
+ISRIgnore 234
+ISRIgnore 235
+ISRIgnore 236
+ISRIgnore 237
+ISRIgnore 238
+ISRIgnore 239
+ISRIgnore 240
+ISRIgnore 241
+ISRIgnore 242
+ISRIgnore 243
+ISRIgnore 244
+ISRIgnore 245
+ISRIgnore 246
+ISRIgnore 247
+ISRIgnore 248
+ISRIgnore 249
+ISRIgnore 250
+ISRIgnore 251
+ISRIgnore 252
+ISRIgnore 253
+ISRIgnore 254
+ISRIgnore 255
diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c
new file mode 100644
index 0000000..af12fff
--- /dev/null
+++ b/kernel/cpu/idt.c
@@ -0,0 +1,204 @@
+#include "stdlib.h"
+#include <lib.h>
+#include <comus/memory.h>
+#include <comus/asm.h>
+
+#include "idt.h"
+#include "pic.h"
+
+#define IDT_SIZE 256
+
+struct idt_entry {
+	uint16_t isr_low;    // low 16 bits of isr
+	uint16_t kernel_cs;  // kernel segment selector
+	uint8_t ist;         // interrupt stack table
+	uint8_t flags;       // gate type, privilege level, present bit
+	uint16_t isr_mid;    // middle 16 bits of isr
+	uint32_t isr_high;   // high 32 bits of isr
+	uint32_t reserved;
+} __attribute__((packed));
+
+struct idtr {
+	uint16_t size;
+	uint64_t address;
+} __attribute__((packed));
+
+// interrupt gate
+#define GATE_64BIT_INT  0x0E
+// trap gate
+#define GATE_64BIT_TRAP 0x0F
+
+// privilege ring allowed to call interrupt
+#define RING0 0x00
+#define RING1 0x20
+#define RING2 0x40
+#define RING3 0x60
+
+// interrupt is present in IDT
+#define PRESENT 0x80
+
+__attribute__((aligned(0x10)))
+static struct idt_entry idt[256];
+
+static struct idtr idtr;
+// from idt.S
+extern void *isr_stub_table[];
+
+// initialize and load the IDT
+void idt_init(void) {
+	// initialize idtr
+	idtr.address = (uint64_t)&idt;
+	idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1;
+
+	// initialize idt
+	for (size_t vector = 0; vector < IDT_SIZE; vector++) {
+		struct idt_entry *entry = &idt[vector];
+
+		uint64_t isr = (uint64_t)isr_stub_table[vector];
+		// interrupts before 0x20 are for cpu exceptions
+		uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT;
+
+		entry->kernel_cs = 0x08; // offset of 1 into GDT
+		entry->ist = 0;
+		entry->flags = PRESENT | RING0 | gate_type;
+		entry->isr_low = isr & 0xffff;
+		entry->isr_mid = (isr >> 16) & 0xffff;
+		entry->isr_high = (isr >> 32) & 0xffffffff;
+		entry->reserved = 0;
+	}
+
+	__asm__ volatile ("lidt %0" : : "m"(idtr));
+}
+
+static void isr_print_regs(struct isr_regs *regs) {
+	printf("rax: %#016lx (%lu)\n", regs->rax, regs->rax);
+	printf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx);
+	printf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx);
+	printf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx);
+	printf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi);
+	printf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi);
+	printf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp);
+	printf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp);
+	printf("r8 : %#016lx (%lu)\n", regs->r8 , regs->r8 );
+	printf("r9 : %#016lx (%lu)\n", regs->r9 , regs->r9 );
+	printf("r10: %#016lx (%lu)\n", regs->r10, regs->r10);
+	printf("r11: %#016lx (%lu)\n", regs->r11, regs->r11);
+	printf("r12: %#016lx (%lu)\n", regs->r12, regs->r12);
+	printf("r13: %#016lx (%lu)\n", regs->r13, regs->r13);
+	printf("r14: %#016lx (%lu)\n", regs->r14, regs->r14);
+	printf("r15: %#016lx (%lu)\n", regs->r15, regs->r15);
+	printf("rip: %#016lx (%lu)\n", regs->rip, regs->rip);
+	printf("rflags: %#016lx (%lu)\n", regs->rflags, regs->rflags);
+	struct rflags *rflags = (struct rflags *)regs->rflags;
+	puts("rflags: ");
+	if (rflags->cf)   puts("CF ");
+	if (rflags->pf)   puts("PF ");
+	if (rflags->af)   puts("AF ");
+	if (rflags->zf)   puts("ZF ");
+	if (rflags->sf)   puts("SF ");
+	if (rflags->tf)   puts("TF ");
+	if (rflags->if_)  puts("IF ");
+	if (rflags->df)   puts("DF ");
+	if (rflags->of)   puts("OF ");
+	if (rflags->iopl) puts("IOPL ");
+	if (rflags->nt)   puts("NT ");
+	if (rflags->md)   puts("MD ");
+	if (rflags->rf)   puts("RF ");
+	if (rflags->vm)   puts("VM ");
+	if (rflags->ac)   puts("AC ");
+	if (rflags->vif)  puts("VIF ");
+	if (rflags->vip)  puts("VIP ");
+	if (rflags->id)   puts("ID ");
+	puts("\n");
+}
+
+#define EX_DEBUG        0x01
+#define EX_BREAKPOINT   0x03
+#define EX_PAGE_FAULT   0x0e
+
+// Intel manual vol 3 ch 6.3.1
+char *EXCEPTIONS[] = {
+	"Division Error",
+	"Debug",
+	"NMI",
+	"Breakpoint",
+	"Overflow",
+	"BOUND Range Exceeded",
+	"Invalid Opcode",
+	"Device Not Available",
+	"Double Fault",
+	"Coprocessor Segment Overrun",
+	"Invalid TSS",
+	"Segment Not Present",
+	"Stack-Segment Fault",
+	"General Protection Fault",
+	"Page Fault",
+	"Reserved",
+	"x87 Floating-Point Error",
+	"Alignment Check",
+	"Machine Check",
+	"SIMD Floaing-Point Exception",
+	"Virtualization Exception",
+	"Control Protection Exception",
+	"Reserved",
+	"Reserved",
+	"Reserved",
+	"Reserved",
+	"Reserved",
+	"Reserved",
+	"Hypervisor Injection Exception",
+	"VMM Communication Exception",
+	"Security Exception",
+	"Reserved",
+};
+
+void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) {
+	uint64_t cr2;
+
+	switch (exception) {
+	case EX_PAGE_FAULT:
+		// page faults store the offending address in cr2
+		__asm__ volatile ("mov %%cr2, %0" : "=r"(cr2));
+		if (!load_page((void *)cr2))
+			return;
+	}
+
+	puts("\n\n!!! EXCEPTION !!!\n");
+	printf("%#02lX %s\n", exception, EXCEPTIONS[exception]);
+	printf("Error code %#lX\n", code);
+
+	if (exception == EX_PAGE_FAULT) {
+		printf("Page fault address: %#016lx\n", cr2);
+	}
+
+	puts("\n");
+
+	isr_print_regs(state);
+
+	puts("\n");
+
+	while (1) {
+		halt();
+	}
+}
+
+void idt_pic_eoi(uint8_t exception) {
+	pic_eoi(exception - PIC_REMAP_OFFSET);
+}
+
+int counter = 0;
+
+void idt_pic_timer(void) {
+	// print a message once we know the timer works
+	// but avoid spamming the logs
+	if (counter == 3) {
+		//kputs("pic timer!\n");
+	}
+	if (counter <= 3) {
+		counter++;
+	}
+}
+
+void idt_pic_keyboard(void) {}
+
+void idt_pic_mouse(void) {}
diff --git a/kernel/cpu/idt.h b/kernel/cpu/idt.h
new file mode 100644
index 0000000..46ef4a3
--- /dev/null
+++ b/kernel/cpu/idt.h
@@ -0,0 +1,68 @@
+/**
+ * @file idt.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * IDT functions
+ */
+
+#ifndef IDT_H_
+#define IDT_H_
+
+#include <stdint.h>
+
+struct isr_regs {
+	uint64_t r15;
+	uint64_t r14;
+	uint64_t r13;
+	uint64_t r12;
+	uint64_t r11;
+	uint64_t r10;
+	uint64_t r9;
+	uint64_t r8;
+	uint64_t rbp;
+	uint64_t rdi;
+	uint64_t rsi;
+	uint64_t rdx;
+	uint64_t rcx;
+	uint64_t rbx;
+	uint64_t rax;
+
+	uint64_t rip;
+	uint64_t cs;
+	uint64_t rflags;
+	uint64_t rsp;
+	uint64_t ss;
+};
+
+struct rflags {
+	uint64_t cf : 1,
+	         : 1,
+	         pf : 1,
+	         : 1,
+	         af : 1,
+	         : 1,
+	         zf : 1,
+	         sf : 1,
+
+	         tf : 1,
+	         if_ : 1,
+	         df : 1,
+	         of : 1,
+	         iopl : 2,
+	         nt : 1,
+	         md : 1,
+
+	         rf : 1,
+	         vm : 1,
+	         ac : 1,
+	         vif : 1,
+	         vip : 1,
+	         id : 1,
+	         : 42;
+};
+
+void idt_init(void);
+
+#endif /* idt.h */
+
diff --git a/kernel/cpu/pic.c b/kernel/cpu/pic.c
new file mode 100644
index 0000000..7065a03
--- /dev/null
+++ b/kernel/cpu/pic.c
@@ -0,0 +1,90 @@
+#include <comus/asm.h>
+
+#include "pic.h"
+
+#define PIC1            0x20        /* IO base address for master PIC */
+#define PIC2            0xA0        /* IO base address for slave PIC */
+#define PIC1_COMMAND    PIC1
+#define PIC1_DATA       (PIC1+1)
+#define PIC2_COMMAND    PIC2
+#define PIC2_DATA       (PIC2+1)
+
+#define PIC_EOI         0x20        /* End-of-interrupt command code */
+
+#define ICW1_ICW4       0x01        /* Indicates that ICW4 will be present */
+#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 pic_remap(void) {
+	uint8_t a1, a2;
+
+	a1 = inb(PIC1_DATA);                        // save masks
+	a2 = inb(PIC2_DATA);
+
+	outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);  // starts the initialization sequence (in cascade mode)
+	io_wait();
+	outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
+	io_wait();
+	outb(PIC1_DATA, PIC_REMAP_OFFSET);          // ICW2: Master PIC vector offset
+	io_wait();
+	outb(PIC2_DATA, PIC_REMAP_OFFSET + 8);      // ICW2: Slave PIC vector offset
+	io_wait();
+	outb(PIC1_DATA, 4);                         // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
+	io_wait();
+	outb(PIC2_DATA, 2);                         // ICW3: tell Slave PIC its cascade identity (0000 0010)
+	io_wait();
+
+	outb(PIC1_DATA, ICW4_8086);                 // ICW4: have the PICs use 8086 mode (and not 8080 mode)
+	io_wait();
+	outb(PIC2_DATA, ICW4_8086);
+	io_wait();
+
+	outb(PIC1_DATA, a1);   // restore saved masks.
+	outb(PIC2_DATA, a2);
+}
+
+void pic_mask(int irq) {
+	uint16_t port;
+	uint8_t mask;
+	if (irq < 8) {
+		port = PIC1_DATA;
+	} else {
+		port = PIC2_DATA;
+		irq -= 8;
+	}
+	mask = inb(port) | (1 << irq);
+	outb(port, mask);
+}
+
+void pic_unmask(int irq) {
+	uint16_t port;
+	uint8_t mask;
+	if (irq < 8) {
+		port = PIC1_DATA;
+	} else {
+		irq -= 8;
+		port = PIC2_DATA;
+	}
+	mask = inb(port) & ~(1 << irq);
+	outb(port, mask);
+}
+
+void pic_disable(void) {
+	outb(PIC1_DATA, 0xff);
+	outb(PIC2_DATA, 0xff);
+}
+
+void pic_eoi(int irq) {
+	if (irq >= 8) {
+		outb(PIC2_COMMAND, PIC_EOI);
+	}
+	outb(PIC1_COMMAND, PIC_EOI);
+}
diff --git a/kernel/cpu/pic.h b/kernel/cpu/pic.h
new file mode 100644
index 0000000..0d1aa3a
--- /dev/null
+++ b/kernel/cpu/pic.h
@@ -0,0 +1,42 @@
+/**
+ * @file pic.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * PIC functions
+ */
+
+#ifndef PIC_H_
+#define PIC_H_
+
+#define PIC_REMAP_OFFSET 0x20
+
+/**
+ * Remaps the pie, i.e. initializes it
+ */
+void pic_remap(void);
+
+/**
+ * Masks an external irq to stop firing until un masked
+ * @param irq - the irq to mask
+ */
+void pic_mask(int irq);
+
+/**
+ * Unmasks an external irq to allow interrupts to continue for that irq
+ * @param irq - the irq to unmask
+ */
+void pic_unmask(int irq);
+
+/**
+ * Disabled the pick
+ */
+void pic_disable(void);
+
+/**
+ * Tells the pick that the interrupt has ended
+ * @param irq - the irq that has ended
+ */
+void pic_eoi(int irq);
+
+#endif /* pic.h */
diff --git a/kernel/include/comus/cpu.h b/kernel/include/comus/cpu.h
new file mode 100644
index 0000000..58fb33d
--- /dev/null
+++ b/kernel/include/comus/cpu.h
@@ -0,0 +1,17 @@
+/**
+ * @file cpu.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * CPU initalization functions
+ */
+
+#ifndef _CPU_H
+#define _CPU_H
+
+/**
+ * Initalize current cpu
+ */
+void cpu_init(void);
+
+#endif /* cpu.h */
diff --git a/kernel/io/io.c b/kernel/io/io.c
index a68114d..11acfdb 100644
--- a/kernel/io/io.c
+++ b/kernel/io/io.c
@@ -1,9 +1,16 @@
 #include <lib.h>
 #include <stdio.h>
+#include <comus/asm.h>
+
+#define PORT 0x3F8
+static void serial_out(uint8_t ch) {
+	// wait for output to be free
+	while ((inb(PORT + 5) & 0x20) == 0);
+	outb(PORT, ch);
+}
 
 void fputc(FILE *stream, char c) {
 	(void) stream;
-	(void) c;
 
-	// FIXME: !!!
+	serial_out(c);
 }
diff --git a/kernel/kernel.c b/kernel/kernel.c
index ac0546c..862425a 100644
--- a/kernel/kernel.c
+++ b/kernel/kernel.c
@@ -1,8 +1,12 @@
+#include <comus/cpu.h>
 #include <comus/memory.h>
+#include <lib.h>
+#include <stdio.h>
 
 void main(void)
 {
-
-	while (1)
-		;
+	cpu_init();
+	memory_init(NULL);
+	printf("halting...\n");
+	while(1);
 }
diff --git a/kernel/kernel.ld b/kernel/kernel.ld
index 8ee6a5b..de5971e 100644
--- a/kernel/kernel.ld
+++ b/kernel/kernel.ld
@@ -6,8 +6,6 @@ SECTIONS
 
 	kernel_start = .;
 
-	. = ALIGN(0x1000);
-
 	.boot : {
 		*(.multiboot)
 	}
@@ -20,12 +18,6 @@ SECTIONS
 
 	. = ALIGN(0x1000);
 
-	.data : {
-		*(.data .data.*)
-	}
-
-	. = ALIGN(0x1000);
-
 	.text : {
 		*(.text .stub .text.* .gnu.linkonce.t.*)
 	}
diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c
index 045afc7..d10cf6d 100644
--- a/kernel/memory/paging.c
+++ b/kernel/memory/paging.c
@@ -573,7 +573,7 @@ void free_pages(void *virt)
 	unmap_pages(kernel_pml4, virt, pages);
 }
 
-int kload_page(void *virt_addr)
+int load_page(void *virt_addr)
 {
 	volatile struct pte *page = get_page(kernel_pml4, virt_addr);
 	if (page == NULL)
diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c
index a9f25af..2b64b72 100644
--- a/kernel/memory/virtalloc.c
+++ b/kernel/memory/virtalloc.c
@@ -103,7 +103,7 @@ void virtaddr_init(void)
 		.is_alloc = false,
 		.is_used = true,
 	};
-	memset(bootstrap_nodes, 0, sizeof(bootstrap_nodes));
+	memsetv(bootstrap_nodes, 0, sizeof(bootstrap_nodes));
 	bootstrap_nodes[0] = init;
 	start_node = &bootstrap_nodes[0];
 }