summaryrefslogtreecommitdiff
path: root/kc/core/cpu.c
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2021-12-19 22:41:15 +0000
committerAda Christine <adachristine18@gmail.com>2021-12-19 22:41:15 +0000
commite303a03e7c96bc5bf7fa93f7b46ce63196893d7a (patch)
treef187b374feec85015d6df1f94db618a3f5cc893f /kc/core/cpu.c
parentbff63a4337eb3388617d230970c5eb2684d6a215 (diff)
moving files around
Diffstat (limited to 'kc/core/cpu.c')
-rw-r--r--kc/core/cpu.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/kc/core/cpu.c b/kc/core/cpu.c
new file mode 100644
index 0000000..ed1a04e
--- /dev/null
+++ b/kc/core/cpu.c
@@ -0,0 +1,225 @@
+#include "cpu.h"
+#include "exceptions.h"
+
+#include <stdint.h>
+
+#define GDT_ENTRIES 16
+#define IDT_ENTRIES 256
+
+#define CODE_SEG_INDEX 1
+#define DATA_SEG_INDEX 2
+#define TASK_SEG_INDEX 3
+
+struct dtr64
+{
+ uint16_t limit;
+ uint64_t base;
+} __attribute__((packed));
+
+struct segment_descriptor
+{
+ uint16_t limit0;
+ uint16_t base0;
+ uint8_t base16;
+ uint8_t access;
+ uint8_t flags_limit16;
+ uint8_t base24;
+} __attribute__((packed));
+
+enum segment_descriptor_type
+{
+ CODE64_SEG,
+ DATA_SEG,
+ TASK64_SEG,
+};
+
+struct gate_descriptor
+{
+ uint16_t offset0;
+ uint16_t selector;
+ uint8_t ist;
+ uint8_t access;
+ uint16_t offset16;
+ uint64_t offset32;
+} __attribute__((packed));
+
+enum gate_descriptor_type
+{
+ INT64_GATE,
+ TRAP64_GATE,
+};
+
+struct task64_segment
+{
+ uint32_t reserved0;
+ uint64_t rsp0;
+ uint64_t rsp1;
+ uint64_t rsp2;
+ uint64_t reserved1;
+ uint64_t ist[7];
+ uint16_t reserved2;
+ uint16_t iomap_base;
+};
+
+static struct segment_descriptor gdt[GDT_ENTRIES];
+static struct gate_descriptor idt[IDT_ENTRIES];
+static struct task64_segment tss;
+
+static void set_gdt(int index,
+ uint64_t base,
+ uint64_t limit,
+ enum segment_descriptor_type type)
+{
+ gdt[index].limit0 = limit & 0xffff;
+ gdt[index].base0 = base & 0xffff;
+ gdt[index].base16 = (base >> 16) & 0xff;
+ gdt[index].flags_limit16 = (limit >> 16) & 0xf;
+ gdt[index].base24 = (base >> 24) & 0xff;
+
+ switch (type)
+ {
+ case CODE64_SEG:
+ gdt[index].access = 0x9a;
+ gdt[index].flags_limit16 |= 0xa0;
+ break;
+ case DATA_SEG:
+ gdt[index].access = 0x92;
+ gdt[index].flags_limit16 |= 0xc0;
+ break;
+ case TASK64_SEG:
+ gdt[index].access = 0x89;
+ //TODO: make this cleaner i don't like it
+ gdt[index+1].limit0 = (base >> 32) & 0xffff;
+ gdt[index+1].base0 = (base >> 48) & 0xffff;
+ break;
+ };
+}
+
+static void set_idt(int vec,
+ uint16_t selector,
+ uint64_t offset,
+ enum gate_descriptor_type type)
+{
+ idt[vec].offset0 = offset & 0xffff;
+ idt[vec].selector = selector;
+ idt[vec].offset16 = (offset >> 16) & 0xffff;
+ idt[vec].offset32 = (offset >> 32) & 0xffffffff;
+
+ switch (type)
+ {
+ case INT64_GATE:
+ idt[vec].access = 0x8e;
+ break;
+ case TRAP64_GATE:
+ idt[vec].access = 0x8f;
+ break;
+ }
+}
+
+void set_ist(int vec, int ist_index)
+{
+ // non-destructively set the ist index.
+ idt[vec].access |= ist_index & 0x7;
+}
+
+static void gdt_init(void)
+{
+ set_gdt(CODE_SEG_INDEX, 0, (uint64_t)-1, CODE64_SEG);
+ set_gdt(DATA_SEG_INDEX, 0, (uint64_t)-1, DATA_SEG);
+ set_gdt(TASK_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG);
+
+ struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt};
+
+ __asm__ volatile
+ (
+ // can't have interrupts during GDT reload
+ // but don't re-enable interrupts if they were already disabled
+ "pushf\n"
+ "cli\n"
+ "lgdt %0\n"
+ "mov %w2, %%ds\n"
+ "mov %w2, %%es\n"
+ "mov %w2, %%fs\n"
+ "mov %w2, %%gs\n"
+ "mov %w2, %%ss\n"
+ // make a far return frame on the stack
+ // [ss] @rsp+8
+ // [rip] @rsp
+ "pushq %1\n"
+ "lea .Lflush(%%rip), %%rax\n"
+ "push %%rax\n"
+ // far return, now we're in the code segment
+ // defined here.
+ "lretq\n"
+ ".Lflush:\n"
+ "ltr %w3\n"
+ "popf\n"
+ // dependency on pre-boot GDT is now gone
+ :
+ : "m"(gdtr),
+ "i"(CODE_SEG_INDEX << 3),
+ "r"(DATA_SEG_INDEX << 3),
+ "r"(TASK_SEG_INDEX << 3)
+ );
+}
+
+static void idt_init(void)
+{
+ struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt};
+
+ __asm__ volatile
+ (
+ // can't have interrupts enabled during IDT reload--obviously.
+ // as with GDT don't re-enable interrupts if they were already
+ // disabled.
+ "pushf\n"
+ "cli\n"
+ "lidt %0\n"
+ "popf\n"
+ // much more straightforward than the gdt code.
+ :: "m"(idtr)
+ );
+}
+
+void cpu_init(void)
+{
+ gdt_init();
+ idt_init();
+ exceptions_init();
+}
+
+void exceptions_init(void)
+{
+ isr_install(PAGE_FAULT_VECTOR, &page_fault_isr, 0, 0);
+}
+
+void isr_install(int vec, void (*isr)(void), int trap, int ist)
+{
+ enum gate_descriptor_type type = INT64_GATE;
+
+ if (trap)
+ {
+ type = TRAP64_GATE;
+ }
+
+ set_idt(vec, CODE_SEG_INDEX << 3, (uint64_t)isr, type);
+ if (ist)
+ {
+ set_ist(vec, ist);
+ }
+}
+
+void ist_install(int ist, void *stack)
+{
+ tss.ist[ist] = (uint64_t)stack;
+}
+
+void int_enable(void)
+{
+ __asm__ ("sti");
+}
+
+void int_disable(void)
+{
+ __asm__ ("cli");
+}