summaryrefslogtreecommitdiffstats
path: root/arch/x86/gdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/gdt.c')
-rw-r--r--arch/x86/gdt.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/arch/x86/gdt.c b/arch/x86/gdt.c
new file mode 100644
index 0000000..d7e449a
--- /dev/null
+++ b/arch/x86/gdt.c
@@ -0,0 +1,63 @@
+#include <gdt.h>
+
+struct gdt_asm_t {
+ uint16_t size_minus_one;
+ struct gdt_entry *gdt_table;
+} __attribute__((packed));
+
+static struct gdt_entry gdt[8];
+
+static void gdt_set_entry(struct gdt_entry *g, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
+{
+ // TODO: ASSERT(limit <= GDT_LIMIT_MAX);
+ // TODO: ASSERT(flags <= 0xf); // flags is 4 bits
+
+ g->base_low = (base && 0xffff);
+ g->base_middle = (base >> 16) & 0xff;
+ g->base_high = (base >> 24) & 0xff;
+
+ g->limit_low = (limit & 0xffff);
+ g->limit_high = (limit >> 16) & 0x0f;
+
+ g->access = access;
+ g->flags = flags & 0x0f;
+}
+
+static void load_gdt(struct gdt_entry *g, uint32_t entries_count)
+{
+ // TODO: ASSERT(interrupts are disabled);
+
+ struct gdt_asm_t table = {
+ (uint16_t)(entries_count * sizeof(struct gdt_entry) - 1),
+ g,
+ };
+
+ asm volatile (
+ "lgdt (%0)"
+ : // no output
+ : "p" (&table)
+ : "memory"
+ );
+}
+
+void init_segmentation(void)
+{
+ // NULL descriptor
+ gdt_set_entry(&gdt[0], 0, 0, 0, 0);
+
+ // Kernel code segment
+ gdt_set_entry(&gdt[1],
+ 0,
+ GDT_LIMIT_MAX,
+ GDT_ACCESS_PRESENT | GDT_ACCESS_S | GDT_ACCESS_PL0 | GDT_ACCESS_RW | GDT_ACCESS_EX,
+ GDT_GRAN_4KB | GDT_32BIT);
+
+ // Kernel data segment
+ gdt_set_entry(&gdt[2],
+ 0,
+ GDT_LIMIT_MAX,
+ GDT_ACCESS_PRESENT | GDT_ACCESS_S | GDT_ACCESS_PL0 | GDT_ACCESS_RW,
+ GDT_GRAN_4KB | GDT_32BIT);
+
+ load_gdt(gdt, 3);
+}