From 1bf5e324005ce7122a195af106cec656960648dc Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sat, 10 Jul 2021 17:41:32 +0200
Subject: a sensible source structure

The idea is that src/kernel/ is only allowed to interface with the
hardware using whatever's defined in src/arch/generic.h. I'll probably
write a small script for checking this later on.

This is a giant commit so I've probably fucked something up. It boots
fine on Bochs and QEMU, so at least there's that.
---
 src/arch/generic.h             |  14 +++++
 src/arch/i386/boot.c           |  16 ++++++
 src/arch/i386/boot.s           |  25 +++++++++
 src/arch/i386/gdt.h            |  16 ++++++
 src/arch/i386/gdt/farjump.s    |   9 +++
 src/arch/i386/gdt/gdt.c        | 119 ++++++++++++++++++++++++++++++++++++++++
 src/arch/i386/interrupts/idt.c |  75 +++++++++++++++++++++++++
 src/arch/i386/interrupts/idt.h |   3 +
 src/arch/i386/interrupts/isr.c |  24 ++++++++
 src/arch/i386/interrupts/isr.h |  15 +++++
 src/arch/i386/multiboot.s      |  11 ++++
 src/arch/i386/sysenter.h       |   2 +
 src/arch/i386/sysenter.s       |  31 +++++++++++
 src/arch/i386/tty.c            |  36 ++++++++++++
 src/arch/i386/tty.h            |   8 +++
 src/kernel/gdt.c               | 121 -----------------------------------------
 src/kernel/gdt.h               |  15 -----
 src/kernel/idt.c               |  75 -------------------------
 src/kernel/idt.h               |   3 -
 src/kernel/isr.c               |  24 --------
 src/kernel/isr.h               |  15 -----
 src/kernel/main.c              |  15 +----
 src/kernel/main.h              |   3 +
 src/kernel/mem.c               |   1 +
 src/kernel/mem.h               |   2 -
 src/kernel/panic.h             |   4 +-
 src/kernel/proc.c              |   2 +-
 src/kernel/tty.c               |  38 -------------
 src/kernel/tty.h               |   8 ---
 src/platform/asm.h             |   9 ---
 src/platform/boot.s            |  47 ----------------
 src/platform/sysenter.s        |  31 -----------
 32 files changed, 413 insertions(+), 404 deletions(-)
 create mode 100644 src/arch/generic.h
 create mode 100644 src/arch/i386/boot.c
 create mode 100644 src/arch/i386/boot.s
 create mode 100644 src/arch/i386/gdt.h
 create mode 100644 src/arch/i386/gdt/farjump.s
 create mode 100644 src/arch/i386/gdt/gdt.c
 create mode 100644 src/arch/i386/interrupts/idt.c
 create mode 100644 src/arch/i386/interrupts/idt.h
 create mode 100644 src/arch/i386/interrupts/isr.c
 create mode 100644 src/arch/i386/interrupts/isr.h
 create mode 100644 src/arch/i386/multiboot.s
 create mode 100644 src/arch/i386/sysenter.h
 create mode 100644 src/arch/i386/sysenter.s
 create mode 100644 src/arch/i386/tty.c
 create mode 100644 src/arch/i386/tty.h
 delete mode 100644 src/kernel/gdt.c
 delete mode 100644 src/kernel/gdt.h
 delete mode 100644 src/kernel/idt.c
 delete mode 100644 src/kernel/idt.h
 delete mode 100644 src/kernel/isr.c
 delete mode 100644 src/kernel/isr.h
 create mode 100644 src/kernel/main.h
 delete mode 100644 src/kernel/tty.c
 delete mode 100644 src/kernel/tty.h
 delete mode 100644 src/platform/asm.h
 delete mode 100644 src/platform/boot.s
 delete mode 100644 src/platform/sysenter.s

diff --git a/src/arch/generic.h b/src/arch/generic.h
new file mode 100644
index 0000000..7807316
--- /dev/null
+++ b/src/arch/generic.h
@@ -0,0 +1,14 @@
+#pragma once
+
+// i have no idea where else to put it
+#define PAGE_SIZE 4096
+
+// src/arch/i386/boot.s
+extern void stack_top;
+
+__attribute__((noreturn))
+void halt_cpu();
+
+// src/arch/i386/sysenter.s
+void sysexit(void (*fun)(), void *stack_top);
+void sysenter_setup();
diff --git a/src/arch/i386/boot.c b/src/arch/i386/boot.c
new file mode 100644
index 0000000..b2b84f0
--- /dev/null
+++ b/src/arch/i386/boot.c
@@ -0,0 +1,16 @@
+#include <arch/i386/gdt.h>
+#include <arch/i386/interrupts/idt.h>
+#include <arch/i386/sysenter.h>
+#include <arch/i386/tty.h>
+#include <kernel/main.h>
+
+void kmain_early() {
+	tty_clear();
+	tty_const("gdt...");
+	gdt_init();
+	tty_const("idt...");
+	idt_init();
+	tty_const("sysenter...");
+	sysenter_setup();
+	kmain();
+}
diff --git a/src/arch/i386/boot.s b/src/arch/i386/boot.s
new file mode 100644
index 0000000..74ec312
--- /dev/null
+++ b/src/arch/i386/boot.s
@@ -0,0 +1,25 @@
+/* a lil stack TODO move to linker.ld */
+.section .bss
+.global stack_top
+.type stack_top, @object
+.align 16
+stack_bottom:
+.skip 16384
+stack_top:
+
+
+.section .text
+.global _start
+.type _start, @function
+_start:
+	mov $stack_top, %esp
+	call kmain_early
+
+.global halt_cpu
+.type halt_cpu, @function
+halt_cpu:
+	cli
+1:	hlt
+	jmp 1b
+
+.size _start, . - _start
diff --git a/src/arch/i386/gdt.h b/src/arch/i386/gdt.h
new file mode 100644
index 0000000..bcb9870
--- /dev/null
+++ b/src/arch/i386/gdt.h
@@ -0,0 +1,16 @@
+#pragma once
+
+enum {
+	SEG_null,
+	// order dictated by SYSENTER
+	SEG_r0code,
+	SEG_r0data,
+	SEG_r3code,
+	SEG_r3data,
+	SEG_TSS,
+
+	SEG_end
+};
+
+void gdt_init();
+void gdt_farjump(int segment);
diff --git a/src/arch/i386/gdt/farjump.s b/src/arch/i386/gdt/farjump.s
new file mode 100644
index 0000000..85d8ba5
--- /dev/null
+++ b/src/arch/i386/gdt/farjump.s
@@ -0,0 +1,9 @@
+.section .text
+.global gdt_farjump
+.type gdt_farjump, @function
+gdt_farjump:
+	/* retf pops off the return address and code segment off the stack.
+	 * it turns out that in the i386 cdecl calling convention they're in
+	 * the correct place already.
+	 */
+	retf
diff --git a/src/arch/i386/gdt/gdt.c b/src/arch/i386/gdt/gdt.c
new file mode 100644
index 0000000..3e0647b
--- /dev/null
+++ b/src/arch/i386/gdt/gdt.c
@@ -0,0 +1,119 @@
+#include <arch/generic.h>
+#include <arch/i386/gdt.h>
+#include <kernel/util.h>
+#include <stdint.h>
+
+
+struct gdt_entry {
+	uint64_t limit_low  : 16;
+	uint64_t base_low   : 24;
+	uint64_t accessed   :  1; // set by the processor
+	                          // CODE        | DATA
+	uint64_t rw         :  1; // readable?   | writeable?
+	uint64_t conforming :  1; // conforming? | expands down?
+	uint64_t code       :  1; // 1           | 0
+
+	uint64_t codeordata :  1; // 1 for everything other than TSS and LDT
+	uint64_t ring       :  2;
+	uint64_t present    :  1; // always 1
+	uint64_t limit_high :  4;
+	uint64_t available  :  1; // ???
+	uint64_t long_mode  :  1;
+	uint64_t x32        :  1;
+	uint64_t gran       :  1; // 1 - 4kb, 0 - 1b
+	uint64_t base_high  :  8;
+} __attribute__((packed));
+
+struct tss_entry {
+	uint32_t prev_tss; // unused
+	uint32_t esp0; // kernel mode stack pointer
+	uint32_t ss0;  // kernel mode stack segment
+	// total size = 0x68 (?) - 3 * sizeof(uint32_t) = 5c
+	uint8_t  _unused[0x5c];
+} __attribute__((packed));
+
+struct lgdt_arg {
+	uint16_t limit;
+	uint32_t base;
+} __attribute__((packed));
+
+static struct gdt_entry GDT[SEG_end];
+static struct tss_entry TSS;
+static struct lgdt_arg lgdt_arg; // probably doesn't need to be global
+
+static void gdt_prepare();
+static void gdt_load();
+
+
+static void gdt_prepare() {
+	GDT[SEG_null].present = 0;
+
+	GDT[SEG_r0data].limit_low  = 0xFFFF;
+	GDT[SEG_r0data].limit_high = 0xF;
+	GDT[SEG_r0data].gran       = 1; // 4KB * 0xFFFFF = (almost) 4GB
+	GDT[SEG_r0data].base_low   = 0;
+	GDT[SEG_r0data].base_high  = 0;
+	GDT[SEG_r0data].accessed   = 0;
+	GDT[SEG_r0data].rw         = 1;
+	GDT[SEG_r0data].conforming = 0;
+	GDT[SEG_r0data].code       = 0;
+	GDT[SEG_r0data].codeordata = 1;
+	GDT[SEG_r0data].ring       = 0;
+	GDT[SEG_r0data].present    = 1;
+	GDT[SEG_r0data].long_mode  = 0; // ???
+	GDT[SEG_r0data].available  = 1; // ???
+	GDT[SEG_r0data].x32        = 1;
+
+	// copy to r0 code
+	GDT[SEG_r0code] = GDT[SEG_r0data];
+	GDT[SEG_r0code].code = 1;
+
+	GDT[SEG_r3data] = GDT[SEG_r0data];
+	GDT[SEG_r3data].ring = 3;
+	GDT[SEG_r3code] = GDT[SEG_r0code];
+	GDT[SEG_r3code].ring = 3;
+
+	// tss
+	memset(&TSS, 0, sizeof(TSS));
+	TSS.ss0 = SEG_r0data << 3; // kernel data segment
+	TSS.esp0 = (uint32_t) &stack_top;
+
+	GDT[SEG_TSS].limit_low  = sizeof(TSS);
+	GDT[SEG_TSS].base_low   = (uint32_t) &TSS;
+	GDT[SEG_TSS].accessed   = 1; // 1 for TSS
+	GDT[SEG_TSS].rw         = 0; // 1 busy / 0 not busy
+	GDT[SEG_TSS].conforming = 0; // 0 for TSS
+	GDT[SEG_TSS].code       = 1; // 32bit
+	GDT[SEG_TSS].codeordata = 0; // is a system entry
+	GDT[SEG_TSS].ring       = 3;
+	GDT[SEG_TSS].present    = 1;
+	GDT[SEG_TSS].limit_high = (sizeof(TSS) >> 16) & 0xf;
+	GDT[SEG_TSS].available  = 0; // 0 for TSS
+	GDT[SEG_TSS].long_mode  = 0;
+	GDT[SEG_TSS].x32        = 0; // idk
+	GDT[SEG_TSS].gran       = 0;
+	GDT[SEG_TSS].base_high  = (((uint32_t) &TSS) >> 24) & 0xff;
+}
+
+static void gdt_load() {
+	lgdt_arg.limit = sizeof(GDT) - 1;
+	lgdt_arg.base = (uint32_t) &GDT;
+	asm("lgdt (%0)" 
+	    : : "r" (&lgdt_arg) : "memory");
+	asm("ltr %%ax"
+	    : : "a" (SEG_TSS << 3 | 3) : "memory");
+
+	// update all segment registers
+	gdt_farjump(SEG_r0code << 3);
+	asm("mov %0, %%ds;"
+	    "mov %0, %%ss;"
+	    "mov %0, %%es;"
+	    "mov %0, %%fs;"
+	    "mov %0, %%gs;"
+	    : : "r" (SEG_r0data << 3) : "memory");
+}
+
+void gdt_init() {
+	gdt_prepare();
+	gdt_load();
+}
diff --git a/src/arch/i386/interrupts/idt.c b/src/arch/i386/interrupts/idt.c
new file mode 100644
index 0000000..4e23118
--- /dev/null
+++ b/src/arch/i386/interrupts/idt.c
@@ -0,0 +1,75 @@
+#include <arch/i386/gdt.h>
+#include <arch/i386/interrupts/idt.h>
+#include <arch/i386/interrupts/isr.h>
+#include <kernel/panic.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct idt_entry {
+	uint16_t offset_low   ;
+	uint16_t code_seg     ;
+	uint8_t  zero         ; // unused, has to be 0
+	uint8_t  type      : 4; // 16/32 bit, task/interrupt/task gate
+	uint8_t  storage   : 1; // 0 for interrupt/trap gates
+	uint8_t  ring      : 2;
+	uint8_t  present   : 1;
+	uint16_t offset_high  ;
+} __attribute__((packed));
+
+// is exactly the same as lgdt_arg, i should combine them into a single struct
+// later
+struct lidt_arg {
+	uint16_t limit;
+	uint32_t base;
+} __attribute__((packed));
+
+
+static struct idt_entry IDT[256];
+static struct lidt_arg lidt_arg;
+
+static inline void idt_add(uint8_t num, bool user, void (*isr));
+static void idt_prepare();
+static void idt_load();
+static void idt_test();
+
+
+static inline void idt_add(uint8_t num, bool user, void (*isr)) {
+	uintptr_t offset = (uintptr_t) isr;
+
+	IDT[num] = (struct idt_entry) {
+		.offset_low  = offset,
+		.offset_high = offset >> 16,
+		.code_seg    = SEG_r0code << 3,
+		.zero        = 0,
+		.present     = 1,
+		.ring        = user ? 3 : 0,
+		.storage     = 0,
+		.type        = 0xE, // 32-bit interrupt gate
+	};
+}
+
+static void idt_prepare() {
+	for (int i = 0; i < 256; i++)
+		IDT[i].present = 0;
+
+	idt_add(0x08, false, isr_double_fault);
+	idt_add(0x0d, false, isr_general_protection_fault);
+	idt_add(0x34, false, isr_test_interrupt);
+}
+
+static void idt_load() {
+	lidt_arg.limit = sizeof(IDT) - 1;
+	lidt_arg.base = (uintptr_t) &IDT;
+	asm("lidt (%0)" : : "r" (&lidt_arg) : "memory");
+}
+
+static void idt_test() {
+	asm("int $0x34" : : : "memory");
+	if (!isr_test_interrupt_called) panic();
+}
+
+void idt_init() {
+	idt_prepare();
+	idt_load();
+	idt_test();
+}
diff --git a/src/arch/i386/interrupts/idt.h b/src/arch/i386/interrupts/idt.h
new file mode 100644
index 0000000..5627657
--- /dev/null
+++ b/src/arch/i386/interrupts/idt.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void idt_init();
diff --git a/src/arch/i386/interrupts/isr.c b/src/arch/i386/interrupts/isr.c
new file mode 100644
index 0000000..03399ea
--- /dev/null
+++ b/src/arch/i386/interrupts/isr.c
@@ -0,0 +1,24 @@
+#include <arch/i386/interrupts/isr.h>
+#include <arch/i386/tty.h>
+#include <kernel/panic.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+bool isr_test_interrupt_called = false;
+
+__attribute__((interrupt))
+void isr_double_fault(struct interrupt_frame *frame) {
+	tty_const("#DF");
+	panic();
+}
+
+__attribute__((interrupt))
+void isr_general_protection_fault(struct interrupt_frame *frame) {
+	tty_const("#GP");
+	panic();
+}
+
+__attribute__((interrupt))
+void isr_test_interrupt(struct interrupt_frame *frame) {
+	isr_test_interrupt_called = true;
+}
diff --git a/src/arch/i386/interrupts/isr.h b/src/arch/i386/interrupts/isr.h
new file mode 100644
index 0000000..150fc46
--- /dev/null
+++ b/src/arch/i386/interrupts/isr.h
@@ -0,0 +1,15 @@
+#pragma once
+#include <stdbool.h>
+
+struct interrupt_frame;
+
+extern bool isr_test_interrupt_called; // used in the self-test in idt.c
+
+__attribute__((interrupt))
+void isr_double_fault(struct interrupt_frame *frame);
+
+__attribute__((interrupt))
+void isr_general_protection_fault(struct interrupt_frame *frame);
+
+__attribute__((interrupt))
+void isr_test_interrupt(struct interrupt_frame *frame);
diff --git a/src/arch/i386/multiboot.s b/src/arch/i386/multiboot.s
new file mode 100644
index 0000000..2194982
--- /dev/null
+++ b/src/arch/i386/multiboot.s
@@ -0,0 +1,11 @@
+.set MAGIC, 0x1BADB002
+.set FLAG_ALIGN,   1<<0 /* align modules on page boundaries */
+.set FLAG_MEMINFO, 1<<1 /* memory map */
+.set FLAGS,        FLAG_ALIGN | FLAG_MEMINFO
+.set CHECKSUM, -(MAGIC + FLAGS)
+
+.section .multiboot
+.align 4
+.long MAGIC
+.long FLAGS
+.long CHECKSUM
diff --git a/src/arch/i386/sysenter.h b/src/arch/i386/sysenter.h
new file mode 100644
index 0000000..b531fe8
--- /dev/null
+++ b/src/arch/i386/sysenter.h
@@ -0,0 +1,2 @@
+#pragma once
+void sysenter_setup();
diff --git a/src/arch/i386/sysenter.s b/src/arch/i386/sysenter.s
new file mode 100644
index 0000000..666c0f0
--- /dev/null
+++ b/src/arch/i386/sysenter.s
@@ -0,0 +1,31 @@
+/* arch/i386/gdt.c */
+.set SEG_r0code, 1
+.set SEG_r3code, 3
+.set SEG_r3data, 4
+
+.set IA32_SYSENTER_CS, 0x174
+
+.section .text
+.global sysexit
+.type sysexit, @function
+sysexit:
+	pop %ecx
+	pop %edx
+
+	mov $(SEG_r3data << 3 | 3), %ax
+	mov %ax, %ds
+	mov %ax, %es
+	mov %ax, %fs
+	mov %ax, %gs
+
+	sysexit
+
+
+.global sysenter_setup
+.type sysenter_setup, @function
+sysenter_setup:
+	xor %edx, %edx
+	mov $(SEG_r0code << 3), %eax
+	mov $IA32_SYSENTER_CS, %ecx
+	wrmsr
+	ret
diff --git a/src/arch/i386/tty.c b/src/arch/i386/tty.c
new file mode 100644
index 0000000..a7c74f5
--- /dev/null
+++ b/src/arch/i386/tty.c
@@ -0,0 +1,36 @@
+#include <arch/i386/tty.h>
+
+struct vga_cell {
+	unsigned char c;
+	unsigned char style;
+} __attribute__((__packed__));
+
+static const size_t     vga_len = 80 * 25;
+static struct vga_cell *vga     = (void*) 0xB8000;
+static size_t           vga_pos = 0;
+
+static void tty_scroll() {
+	for (int i = 0; i < vga_len - 80; i++) {
+		vga[i] = vga[i + 80];
+	}
+	vga_pos -= 80;
+}
+
+void tty_putchar(char c)
+{
+	if (vga_pos >= vga_len - 80) tty_scroll();
+	vga[vga_pos++].c = c;
+}
+
+void tty_write(const char *buf, size_t len)
+{
+	for (size_t i = 0; i < len; i++) {
+		tty_putchar(buf[i]);
+	}
+}
+
+void tty_clear() {
+	for (size_t i = 0; i < vga_len; i++)
+		vga[i].c = ' ';
+	vga_pos = 0;
+}
diff --git a/src/arch/i386/tty.h b/src/arch/i386/tty.h
new file mode 100644
index 0000000..3dc1525
--- /dev/null
+++ b/src/arch/i386/tty.h
@@ -0,0 +1,8 @@
+#pragma once
+#include <stddef.h>
+
+void tty_putchar(char c);
+void tty_write(const char *buf, size_t len);
+void tty_clear();
+
+#define tty_const(str) tty_write(str, sizeof(str) - 1)
diff --git a/src/kernel/gdt.c b/src/kernel/gdt.c
deleted file mode 100644
index b0d6320..0000000
--- a/src/kernel/gdt.c
+++ /dev/null
@@ -1,121 +0,0 @@
-#include <kernel/gdt.h>
-#include <kernel/util.h>
-#include <stdint.h>
-
-extern void stack_top; // platform/boot.s
-
-struct gdt_entry {
-	uint64_t limit_low  : 16;
-	uint64_t base_low   : 24;
-	uint64_t accessed   :  1; // set by the processor
-	                          // CODE        | DATA
-	uint64_t rw         :  1; // readable?   | writeable?
-	uint64_t conforming :  1; // conforming? | expands down?
-	uint64_t code       :  1; // 1           | 0
-
-	uint64_t codeordata :  1; // 1 for everything other than TSS and LDT
-	uint64_t ring       :  2;
-	uint64_t present    :  1; // always 1
-	uint64_t limit_high :  4;
-	uint64_t available  :  1; // ???
-	uint64_t long_mode  :  1;
-	uint64_t x32        :  1;
-	uint64_t gran       :  1; // 1 - 4kb, 0 - 1b
-	uint64_t base_high  :  8;
-} __attribute__((packed));
-
-struct tss_entry {
-	uint32_t prev_tss; // unused
-	uint32_t esp0; // kernel mode stack pointer
-	uint32_t ss0;  // kernel mode stack segment
-	// total size = 0x68 (?) - 3 * sizeof(uint32_t) = 5c
-	uint8_t  _unused[0x5c];
-} __attribute__((packed));
-
-struct lgdt_arg {
-	uint16_t limit;
-	uint32_t base;
-} __attribute__((packed));
-
-static struct gdt_entry GDT[SEG_end];
-static struct tss_entry TSS;
-static struct lgdt_arg lgdt_arg; // probably doesn't need to be global
-
-static void gdt_prepare();
-static void gdt_load();
-
-
-static void gdt_prepare() {
-	GDT[SEG_null].present = 0;
-
-	GDT[SEG_r0data].limit_low  = 0xFFFF;
-	GDT[SEG_r0data].limit_high = 0xF;
-	GDT[SEG_r0data].gran       = 1; // 4KB * 0xFFFFF = (almost) 4GB
-	GDT[SEG_r0data].base_low   = 0;
-	GDT[SEG_r0data].base_high  = 0;
-	GDT[SEG_r0data].accessed   = 0;
-	GDT[SEG_r0data].rw         = 1;
-	GDT[SEG_r0data].conforming = 0;
-	GDT[SEG_r0data].code       = 0;
-	GDT[SEG_r0data].codeordata = 1;
-	GDT[SEG_r0data].ring       = 0;
-	GDT[SEG_r0data].present    = 1;
-	GDT[SEG_r0data].long_mode  = 0; // ???
-	GDT[SEG_r0data].available  = 1; // ???
-	GDT[SEG_r0data].x32        = 1;
-
-	// copy to r0 code
-	GDT[SEG_r0code] = GDT[SEG_r0data];
-	GDT[SEG_r0code].code = 1;
-
-	GDT[SEG_r3data] = GDT[SEG_r0data];
-	GDT[SEG_r3data].ring = 3;
-	GDT[SEG_r3code] = GDT[SEG_r0code];
-	GDT[SEG_r3code].ring = 3;
-
-	// tss
-	memset(&TSS, 0, sizeof(TSS));
-	TSS.ss0 = SEG_r0data << 3; // kernel data segment
-	TSS.esp0 = (uint32_t) &stack_top;
-
-	GDT[SEG_TSS].limit_low  = sizeof(TSS);
-	GDT[SEG_TSS].base_low   = (uint32_t) &TSS;
-	GDT[SEG_TSS].accessed   = 1; // 1 for TSS
-	GDT[SEG_TSS].rw         = 0; // 1 busy / 0 not busy
-	GDT[SEG_TSS].conforming = 0; // 0 for TSS
-	GDT[SEG_TSS].code       = 1; // 32bit
-	GDT[SEG_TSS].codeordata = 0; // is a system entry
-	GDT[SEG_TSS].ring       = 3;
-	GDT[SEG_TSS].present    = 1;
-	GDT[SEG_TSS].limit_high = (sizeof(TSS) >> 16) & 0xf;
-	GDT[SEG_TSS].available  = 0; // 0 for TSS
-	GDT[SEG_TSS].long_mode  = 0;
-	GDT[SEG_TSS].x32        = 0; // idk
-	GDT[SEG_TSS].gran       = 0;
-	GDT[SEG_TSS].base_high  = (((uint32_t) &TSS) >> 24) & 0xff;
-}
-
-void change_cs(int seg); // temporary
-
-static void gdt_load() {
-	lgdt_arg.limit = sizeof(GDT) - 1;
-	lgdt_arg.base = (uint32_t) &GDT;
-	asm("lgdt (%0)" 
-	    : : "r" (&lgdt_arg) : "memory");
-	asm("ltr %%ax"
-	    : : "a" (SEG_TSS << 3 | 3) : "memory");
-
-	// update all segment registers
-	change_cs(SEG_r0code << 3);
-	asm("mov %0, %%ds;"
-	    "mov %0, %%ss;"
-	    "mov %0, %%es;"
-	    "mov %0, %%fs;"
-	    "mov %0, %%gs;"
-	    : : "r" (SEG_r0data << 3) : "memory");
-}
-
-void gdt_init() {
-	gdt_prepare();
-	gdt_load();
-}
diff --git a/src/kernel/gdt.h b/src/kernel/gdt.h
deleted file mode 100644
index 9e5a6a5..0000000
--- a/src/kernel/gdt.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-enum {
-	SEG_null,
-	// order dictated by SYSENTER
-	SEG_r0code,
-	SEG_r0data,
-	SEG_r3code,
-	SEG_r3data,
-	SEG_TSS,
-
-	SEG_end
-};
-
-void gdt_init();
diff --git a/src/kernel/idt.c b/src/kernel/idt.c
deleted file mode 100644
index 65f511f..0000000
--- a/src/kernel/idt.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include <kernel/gdt.h>
-#include <kernel/idt.h>
-#include <kernel/isr.h>
-#include <kernel/panic.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-struct idt_entry {
-	uint16_t offset_low   ;
-	uint16_t code_seg     ;
-	uint8_t  zero         ; // unused, has to be 0
-	uint8_t  type      : 4; // 16/32 bit, task/interrupt/task gate
-	uint8_t  storage   : 1; // 0 for interrupt/trap gates
-	uint8_t  ring      : 2;
-	uint8_t  present   : 1;
-	uint16_t offset_high  ;
-} __attribute__((packed));
-
-// is exactly the same as lgdt_arg, i should combine them into a single struct
-// later
-struct lidt_arg {
-	uint16_t limit;
-	uint32_t base;
-} __attribute__((packed));
-
-
-static struct idt_entry IDT[256];
-static struct lidt_arg lidt_arg;
-
-static inline void idt_add(uint8_t num, bool user, void (*isr));
-static void idt_prepare();
-static void idt_load();
-static void idt_test();
-
-
-static inline void idt_add(uint8_t num, bool user, void (*isr)) {
-	uintptr_t offset = (uintptr_t) isr;
-
-	IDT[num] = (struct idt_entry) {
-		.offset_low  = offset,
-		.offset_high = offset >> 16,
-		.code_seg    = SEG_r0code << 3,
-		.zero        = 0,
-		.present     = 1,
-		.ring        = user ? 3 : 0,
-		.storage     = 0,
-		.type        = 0xE, // 32-bit interrupt gate
-	};
-}
-
-static void idt_prepare() {
-	for (int i = 0; i < 256; i++)
-		IDT[i].present = 0;
-
-	idt_add(0x08, false, isr_double_fault);
-	idt_add(0x0d, false, isr_general_protection_fault);
-	idt_add(0x34, false, isr_test_interrupt);
-}
-
-static void idt_load() {
-	lidt_arg.limit = sizeof(IDT) - 1;
-	lidt_arg.base = (uintptr_t) &IDT;
-	asm("lidt (%0)" : : "r" (&lidt_arg) : "memory");
-}
-
-static void idt_test() {
-	asm("int $0x34" : : : "memory");
-	if (!isr_test_interrupt_called) panic();
-}
-
-void idt_init() {
-	idt_prepare();
-	idt_load();
-	idt_test();
-}
diff --git a/src/kernel/idt.h b/src/kernel/idt.h
deleted file mode 100644
index 5627657..0000000
--- a/src/kernel/idt.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void idt_init();
diff --git a/src/kernel/isr.c b/src/kernel/isr.c
deleted file mode 100644
index b715de0..0000000
--- a/src/kernel/isr.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include <kernel/isr.h>
-#include <kernel/panic.h>
-#include <kernel/tty.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-bool isr_test_interrupt_called = false;
-
-__attribute__((interrupt))
-void isr_double_fault(struct interrupt_frame *frame) {
-	tty_const("#DF");
-	panic();
-}
-
-__attribute__((interrupt))
-void isr_general_protection_fault(struct interrupt_frame *frame) {
-	tty_const("#GP");
-	panic();
-}
-
-__attribute__((interrupt))
-void isr_test_interrupt(struct interrupt_frame *frame) {
-	isr_test_interrupt_called = true;
-}
diff --git a/src/kernel/isr.h b/src/kernel/isr.h
deleted file mode 100644
index 150fc46..0000000
--- a/src/kernel/isr.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-#include <stdbool.h>
-
-struct interrupt_frame;
-
-extern bool isr_test_interrupt_called; // used in the self-test in idt.c
-
-__attribute__((interrupt))
-void isr_double_fault(struct interrupt_frame *frame);
-
-__attribute__((interrupt))
-void isr_general_protection_fault(struct interrupt_frame *frame);
-
-__attribute__((interrupt))
-void isr_test_interrupt(struct interrupt_frame *frame);
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 0193514..aa67d7c 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -1,22 +1,11 @@
-#include <kernel/gdt.h>
-#include <kernel/idt.h>
+#include <arch/generic.h>
 #include <kernel/mem.h>
 #include <kernel/panic.h>
 #include <kernel/proc.h>
-#include <kernel/tty.h>
-#include <platform/asm.h>
 
 void r3_test();
 
-void kmain()
-{
-	tty_clear();
-	tty_const("gdt...");
-	gdt_init();
-	tty_const("idt...");
-	idt_init();
-	tty_const("sysenter...");
-	sysenter_setup();
+void kmain() {
 	tty_const("mem...");
 	mem_init();
 
diff --git a/src/kernel/main.h b/src/kernel/main.h
new file mode 100644
index 0000000..6f27386
--- /dev/null
+++ b/src/kernel/main.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void kmain();
diff --git a/src/kernel/mem.c b/src/kernel/mem.c
index 08eb285..f383e8b 100644
--- a/src/kernel/mem.c
+++ b/src/kernel/mem.c
@@ -1,3 +1,4 @@
+#include <arch/generic.h>
 #include <kernel/mem.h>
 
 extern void *_kernel_end;
diff --git a/src/kernel/mem.h b/src/kernel/mem.h
index e8e6a4f..efa65d6 100644
--- a/src/kernel/mem.h
+++ b/src/kernel/mem.h
@@ -1,8 +1,6 @@
 #pragma once
 #include <stddef.h>
 
-#define PAGE_SIZE 4096
-
 void mem_init();
 
 // allocates `pages` consecutive pages
diff --git a/src/kernel/panic.h b/src/kernel/panic.h
index 7d2ea5f..54a0b8b 100644
--- a/src/kernel/panic.h
+++ b/src/kernel/panic.h
@@ -1,6 +1,6 @@
 #pragma once
-#include <kernel/tty.h>
-#include <platform/asm.h>
+#include <arch/generic.h>
+#include <arch/i386/tty.h> // TODO abstract away
 
 // dumb c shit
 #define panic_tostr2(x) #x
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 776238c..7d42bce 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -1,6 +1,6 @@
+#include <arch/generic.h>
 #include <kernel/mem.h>
 #include <kernel/proc.h>
-#include <platform/asm.h>
 
 struct process *process_current;
 
diff --git a/src/kernel/tty.c b/src/kernel/tty.c
deleted file mode 100644
index 5c4c47d..0000000
--- a/src/kernel/tty.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* will be moved to userspace later on */
-
-#include <kernel/tty.h>
-
-struct vga_cell {
-	unsigned char c;
-	unsigned char style;
-} __attribute__((__packed__));
-
-static const size_t     vga_len = 80 * 25;
-static struct vga_cell *vga     = (void*) 0xB8000;
-static size_t           vga_pos = 0;
-
-static void tty_scroll() {
-	for (int i = 0; i < vga_len - 80; i++) {
-		vga[i] = vga[i + 80];
-	}
-	vga_pos -= 80;
-}
-
-void tty_putchar(char c)
-{
-	if (vga_pos >= vga_len - 80) tty_scroll();
-	vga[vga_pos++].c = c;
-}
-
-void tty_write(const char *buf, size_t len)
-{
-	for (size_t i = 0; i < len; i++) {
-		tty_putchar(buf[i]);
-	}
-}
-
-void tty_clear() {
-	for (size_t i = 0; i < vga_len; i++)
-		vga[i].c = ' ';
-	vga_pos = 0;
-}
diff --git a/src/kernel/tty.h b/src/kernel/tty.h
deleted file mode 100644
index 3dc1525..0000000
--- a/src/kernel/tty.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-#include <stddef.h>
-
-void tty_putchar(char c);
-void tty_write(const char *buf, size_t len);
-void tty_clear();
-
-#define tty_const(str) tty_write(str, sizeof(str) - 1)
diff --git a/src/platform/asm.h b/src/platform/asm.h
deleted file mode 100644
index 6f72617..0000000
--- a/src/platform/asm.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-// boot.s
-__attribute__((noreturn))
-void halt_cpu();
-
-// sysenter.c
-void sysexit(void (*fun)(), void *stack_top);
-void sysenter_setup();
diff --git a/src/platform/boot.s b/src/platform/boot.s
deleted file mode 100644
index d5bfda5..0000000
--- a/src/platform/boot.s
+++ /dev/null
@@ -1,47 +0,0 @@
-.set MAGIC, 0x1BADB002
-.set FLAG_ALIGN,   1<<0 /* align modules on page boundaries */
-.set FLAG_MEMINFO, 1<<1 /* memory map */
-.set FLAGS,        FLAG_ALIGN | FLAG_MEMINFO
-.set CHECKSUM, -(MAGIC + FLAGS)
-
-.section .multiboot
-.align 4
-.long MAGIC
-.long FLAGS
-.long CHECKSUM
-
-/* a lil stack */
-.section .bss
-.global stack_top
-.type stack_top, @object
-.align 16
-stack_bottom:
-.skip 16384
-stack_top:
-
-
-.section .text
-.global _start
-.type _start, @function
-_start:
-	mov $stack_top, %esp
-	call kmain
-
-.global halt_cpu
-.type halt_cpu, @function
-halt_cpu:
-	cli
-1:	hlt
-	jmp 1b
-
-// temporary, will be moved to another file soon
-.global change_cs
-.type change_cs, @function
-change_cs:
-	/* retf pops off the return address and code segment off the stack.
-	 * it turns out that in the i386 cdecl calling convention they're in
-	 * the correct place already.
-	 */
-	retf
-
-.size _start, . - _start
diff --git a/src/platform/sysenter.s b/src/platform/sysenter.s
deleted file mode 100644
index 270dc08..0000000
--- a/src/platform/sysenter.s
+++ /dev/null
@@ -1,31 +0,0 @@
-/* kernel/gdt.c */
-.set SEG_r0code, 1
-.set SEG_r3code, 3
-.set SEG_r3data, 4
-
-.set IA32_SYSENTER_CS, 0x174
-
-.section .text
-.global sysexit
-.type sysexit, @function
-sysexit:
-	pop %ecx
-	pop %edx
-
-	mov $(SEG_r3data << 3 | 3), %ax
-	mov %ax, %ds
-	mov %ax, %es
-	mov %ax, %fs
-	mov %ax, %gs
-
-	sysexit
-
-
-.global sysenter_setup
-.type sysenter_setup, @function
-sysenter_setup:
-	xor %edx, %edx
-	mov $(SEG_r0code << 3), %eax
-	mov $IA32_SYSENTER_CS, %ecx
-	wrmsr
-	ret
-- 
cgit v1.2.3