diff options
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/i386/gdt/gdt.c | 98 |
1 files changed, 53 insertions, 45 deletions
diff --git a/src/arch/i386/gdt/gdt.c b/src/arch/i386/gdt/gdt.c index 3e0647b..c61002b 100644 --- a/src/arch/i386/gdt/gdt.c +++ b/src/arch/i386/gdt/gdt.c @@ -1,6 +1,7 @@ #include <arch/generic.h> #include <arch/i386/gdt.h> #include <kernel/util.h> +#include <stdbool.h> #include <stdint.h> @@ -25,11 +26,10 @@ struct gdt_entry { } __attribute__((packed)); struct tss_entry { - uint32_t prev_tss; // unused + uint32_t _unused0; uint32_t esp0; // kernel mode stack pointer uint32_t ss0; // kernel mode stack segment - // total size = 0x68 (?) - 3 * sizeof(uint32_t) = 5c - uint8_t _unused[0x5c]; + uint8_t _unused1[0x5c]; } __attribute__((packed)); struct lgdt_arg { @@ -41,65 +41,73 @@ static struct gdt_entry GDT[SEG_end]; static struct tss_entry TSS; static struct lgdt_arg lgdt_arg; // probably doesn't need to be global +static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code); static void gdt_prepare(); static void gdt_load(); +static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code) { + *entry = (struct gdt_entry) { + // set up the identity mapping + .limit_low = 0xFFFF, + .limit_high = 0xF, + .gran = 1, // 4KB * 0xFFFFF = (almost) 4GB + .base_low = 0, + .base_high = 0, + + .ring = ring, + .code = code, + + .accessed = 0, + .rw = 1, + .conforming = 0, + .codeordata = 1, + .present = 1, + .long_mode = 0, // ??? + .available = 1, // ??? + .x32 = 1, + }; +} + static void gdt_prepare() { GDT[SEG_null].present = 0; - GDT[SEG_r0data].limit_low = 0xFFFF; - GDT[SEG_r0data].limit_high = 0xF; - GDT[SEG_r0data].gran = 1; // 4KB * 0xFFFFF = (almost) 4GB - GDT[SEG_r0data].base_low = 0; - GDT[SEG_r0data].base_high = 0; - GDT[SEG_r0data].accessed = 0; - GDT[SEG_r0data].rw = 1; - GDT[SEG_r0data].conforming = 0; - GDT[SEG_r0data].code = 0; - GDT[SEG_r0data].codeordata = 1; - GDT[SEG_r0data].ring = 0; - GDT[SEG_r0data].present = 1; - GDT[SEG_r0data].long_mode = 0; // ??? - GDT[SEG_r0data].available = 1; // ??? - GDT[SEG_r0data].x32 = 1; - - // copy to r0 code - GDT[SEG_r0code] = GDT[SEG_r0data]; - GDT[SEG_r0code].code = 1; - - GDT[SEG_r3data] = GDT[SEG_r0data]; - GDT[SEG_r3data].ring = 3; - GDT[SEG_r3code] = GDT[SEG_r0code]; - GDT[SEG_r3code].ring = 3; + gdt_fillout(&GDT[SEG_r0code], 0, true); + gdt_fillout(&GDT[SEG_r0data], 0, false); + gdt_fillout(&GDT[SEG_r3code], 3, true); + gdt_fillout(&GDT[SEG_r3data], 3, false); // tss memset(&TSS, 0, sizeof(TSS)); TSS.ss0 = SEG_r0data << 3; // kernel data segment - TSS.esp0 = (uint32_t) &stack_top; - - GDT[SEG_TSS].limit_low = sizeof(TSS); - GDT[SEG_TSS].base_low = (uint32_t) &TSS; - GDT[SEG_TSS].accessed = 1; // 1 for TSS - GDT[SEG_TSS].rw = 0; // 1 busy / 0 not busy - GDT[SEG_TSS].conforming = 0; // 0 for TSS - GDT[SEG_TSS].code = 1; // 32bit - GDT[SEG_TSS].codeordata = 0; // is a system entry - GDT[SEG_TSS].ring = 3; - GDT[SEG_TSS].present = 1; - GDT[SEG_TSS].limit_high = (sizeof(TSS) >> 16) & 0xf; - GDT[SEG_TSS].available = 0; // 0 for TSS - GDT[SEG_TSS].long_mode = 0; - GDT[SEG_TSS].x32 = 0; // idk - GDT[SEG_TSS].gran = 0; - GDT[SEG_TSS].base_high = (((uint32_t) &TSS) >> 24) & 0xff; + TSS.esp0 = (uintptr_t) &stack_top; + + GDT[SEG_TSS] = (struct gdt_entry) { + .limit_low = sizeof(TSS), + .limit_high = sizeof(TSS) >> 16, + .gran = 0, + .base_low = (uintptr_t) &TSS, + .base_high = ((uintptr_t) &TSS) >> 24, + + .accessed = 1, // 1 for TSS + .rw = 0, // 1 busy / 0 not busy + .conforming = 0, // 0 for TSS + .code = 1, // 32bit + .codeordata = 0, // is a system entry + .ring = 3, + .present = 1, + .available = 0, // 0 for TSS + .long_mode = 0, + .x32 = 0, // idk + }; } static void gdt_load() { lgdt_arg.limit = sizeof(GDT) - 1; - lgdt_arg.base = (uint32_t) &GDT; + lgdt_arg.base = (uintptr_t) &GDT; asm("lgdt (%0)" : : "r" (&lgdt_arg) : "memory"); + asm("ltr %%ax" : : "a" (SEG_TSS << 3 | 3) : "memory"); |