Orion
Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)diff --git a/proc/gdt.c b/proc/gdt.c new file mode 100644 index 0000000..6d9a7c7 --- /dev/null +++ b/proc/gdt.c @@ -0,0 +1,104 @@ +/* + * This file deals with the Global Descriptor Table. It creates a simple GDT, + * suitable for use in the Kernel, and attaches a TSS to the end. The TSS, + * which can be used to switch from ring 3 to ring 0, allows processes access to + * all IO ports. + */ + +#include <stdint.h> +#include "../mem/heap.h" +#include "../mem/mem.h" +#include "../mem/frame.h" +#include "../proc/proc.h" +#include "../screen.h" + +#define GDT_ENTRIES 6 + +/* Structure for GDT entry */ +static struct GDTEntry { + uint16_t limitLower, baseLower; + uint8_t baseMiddle, access, gran, baseHigher; +} __attribute__((packed)) *GDT; + +/* Structure for TSS entry */ +static struct TSSEntry { + uint32_t prevTSS; + uint32_t esp0, ss0; + uint32_t esp1, ss1; + uint32_t esp2, ss2; + uint32_t cr3, eip, eflags; + uint32_t eax, ecx, edx, ebx; + uint32_t esp, ebp, esi, edi; + uint32_t es, cs, ss, ds, fs, gs; + uint32_t ldt; + uint16_t trap, iomapBase; +// uint32_t iomap[2048]; +} __attribute__((packed)) *TSS; /* Per CPU */ + +void load_gdt(uint32_t gdtPtr); +void load_tss(void); + +/* Set a gate of the GDT */ +static void +gdt_set_gate(uint8_t num, uint32_t base, uint32_t limit, + uint8_t access, uint8_t gran) +{ + GDT[num].baseLower = (base & 0xFFFF); + GDT[num].baseMiddle = (base >> 16) & 0xFF; + GDT[num].baseHigher = (base >> 24) & 0xFF; + GDT[num].limitLower = (limit & 0xFFFF); + GDT[num].gran = (limit >> 16) & 0x0F; + GDT[num].gran |= gran & 0xF0; + GDT[num].access = access; +} + +/* Create a TSS */ +static void +write_tss(uint8_t num, uint32_t esp) +{ + uint32_t base = (uint32_t) TSS; + uint32_t limit = sizeof(struct TSSEntry) - 1; + + gdt_set_gate(num, base, limit, 0xE9, 0x00); + num -= 5; + memset(&TSS[num], 0, sizeof(struct TSSEntry)); + TSS[num].ss0 = 0x10; + TSS[num].esp0 = esp; + TSS[num].cs = 0x08 | 0; + TSS[num].ds = TSS[num].es = TSS[num].ss = 0x10 | 0; + TSS[num].fs = TSS[num].gs = 0x10 | 3; + TSS[num].iomapBase = 104; +} + +/* Initialise the Kernel GDT */ +void +init_gdt(void) +{ + GDT = (void *) alloc_frames(1); + TSS = (void *) (GDT + GDT_ENTRIES); + kprintf("Loaded GDT @ %#.8x, TSS @ %#.8x", GDT, TSS); +} + +/* Load the Kernel GDT */ +void +cpu_load_gdt(void) +{ + memset(GDT, 0, sizeof(GDT[0]) * GDT_ENTRIES); + + gdt_set_gate(0, 0x00000000, 0x00000000, 0x00, 0x00); /* Null segment */ + /* Ring 0 */ + gdt_set_gate(1, 0x00000000, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */ + gdt_set_gate(2, 0x00000000, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */ + /* Ring 3 */ + gdt_set_gate(3, 0x00000000, 0xFFFFFFFF, 0xFA, 0xCF); /* Code segment */ + gdt_set_gate(4, 0x00000000, 0xFFFFFFFF, 0xF2, 0xCF); /* Data segment */ + /* TSS */ + write_tss(5, 0xF0800000 - sizeof(uintptr_t)); + + uint16_t gdtPtr[3]; + gdtPtr[0] = (sizeof(GDT[0]) * GDT_ENTRIES) - 1; + gdtPtr[1] = ((uint32_t) GDT) & 0xFFFF; + gdtPtr[2] = ((uint32_t) GDT) >> 16; + load_gdt((uint32_t) &gdtPtr); + load_tss(); +}