summaryrefslogtreecommitdiff
path: root/kernel/cpu/gdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cpu/gdt.c')
-rw-r--r--kernel/cpu/gdt.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/kernel/cpu/gdt.c b/kernel/cpu/gdt.c
new file mode 100644
index 0000000..28853cf
--- /dev/null
+++ b/kernel/cpu/gdt.c
@@ -0,0 +1,72 @@
+#include "gdt.h"
+
+extern void flush_tss(void);
+extern void load_gdt(void *);
+
+typedef struct tss_entry_struct tss_entry_t;
+
+tss_entry_t tss_entry;
+
+typedef union {
+ struct GDT_Entry s;
+ uint64_t raw;
+} GDT_Entry;
+
+GDT_Entry gdt_entries[6] = {0};
+GDT_Pointer gdtr;
+
+extern uint32_t inital_esp;
+void write_tss(struct GDT_Entry *gdt_entry) {
+ uint32_t base = (uint32_t)&tss_entry;
+ uint32_t limit = sizeof(tss_entry);
+
+ gdt_entry->limit_low = limit;
+ gdt_entry->base_low = base;
+ gdt_entry->accessed = 1;
+ gdt_entry->read_write = 0;
+ gdt_entry->conforming_expand_down = 0;
+ gdt_entry->code = 1;
+ gdt_entry->code_data_segment = 0;
+ gdt_entry->DPL = 0;
+ gdt_entry->present = 1;
+ gdt_entry->limit_high = limit >> 16;
+ gdt_entry->available = 0;
+ gdt_entry->long_mode = 0;
+ gdt_entry->big = 0;
+ gdt_entry->gran = 0;
+ gdt_entry->base_high = (base & ((uint32_t)0xff << 24)) >> 24;
+
+ memset(&tss_entry, 0, sizeof tss_entry);
+ tss_entry.ss0 = GDT_KERNEL_DATA_SEGMENT * GDT_ENTRY_SIZE;
+ register uint32_t esp asm("esp");
+ tss_entry.esp0 = esp;
+}
+
+void gdt_init() {
+ gdt_entries[GDT_NULL_SEGMENT].raw = 0x0;
+ gdt_entries[GDT_KERNEL_CODE_SEGMENT].raw =
+ 0xCF9A000000FFFF; // Kernel code segment
+ gdt_entries[GDT_KERNEL_DATA_SEGMENT].raw =
+ 0xCF92000000FFFF; // Kernel data segment
+
+ // Usermode code segment
+ memcpy(&gdt_entries[GDT_USERMODE_CODE_SEGMENT],
+ &gdt_entries[GDT_KERNEL_CODE_SEGMENT], GDT_ENTRY_SIZE);
+
+ // Usermode data segment
+ memcpy(&gdt_entries[GDT_USERMODE_DATA_SEGMENT],
+ &gdt_entries[GDT_KERNEL_DATA_SEGMENT], GDT_ENTRY_SIZE);
+
+ // Set DPL to 3 to indicate that the segment is in ring 3
+ gdt_entries[GDT_USERMODE_CODE_SEGMENT].s.DPL = 3;
+ gdt_entries[GDT_USERMODE_DATA_SEGMENT].s.DPL = 3;
+
+ write_tss((struct GDT_Entry *)&gdt_entries[GDT_TSS_SEGMENT]);
+
+ gdtr.offset = (uint32_t)&gdt_entries;
+ gdtr.size = sizeof(gdt_entries) - 1;
+
+ asm("cli");
+ load_gdt(&gdtr);
+ flush_tss();
+}