/* * 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 #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(); }