diff options
Diffstat (limited to 'src/kernel/arch/amd64/32/gdt.c')
-rw-r--r-- | src/kernel/arch/amd64/32/gdt.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/kernel/arch/amd64/32/gdt.c b/src/kernel/arch/amd64/32/gdt.c new file mode 100644 index 0000000..2229330 --- /dev/null +++ b/src/kernel/arch/amd64/32/gdt.c @@ -0,0 +1,118 @@ +#include <kernel/arch/amd64/32/gdt.h> +#include <kernel/arch/generic.h> +#include <stdbool.h> +#include <stdint.h> + +extern char _isr_mini_stack; + +struct gdt_entry { + uint64_t limit_low : 16; + uint64_t base_low : 24; + uint64_t accessed : 1; // set by the processor + // CODE | DATA + uint64_t rw : 1; // readable? | writeable? + uint64_t conforming : 1; // conforming? | expands down? + uint64_t code : 1; // 1 | 0 + + uint64_t codeordata : 1; // 1 for everything other than TSS and LDT + uint64_t ring : 2; + uint64_t present : 1; // always 1 + uint64_t limit_high : 4; + uint64_t available : 1; // ??? + uint64_t long_mode : 1; + uint64_t x32 : 1; + uint64_t gran : 1; // 1 - 4kb, 0 - 1b + uint64_t base_high : 8; +} __attribute__((packed)); + +struct tss_entry { + uint32_t reserved0; + uint64_t rsp[3]; + uint64_t ist[8]; + uint64_t reserved2; + uint16_t reserved3; + uint16_t iopb; +} __attribute__((packed)); + +struct lgdt_arg { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +__attribute__((section(".shared"))) +struct gdt_entry GDT[SEG_end]; +__attribute__((section(".shared"))) +struct tss_entry TSS; + +struct lgdt_arg lgdt_arg; + + +static void *memset32(void *s, int c, size_t n) { + uint8_t *s2 = s; + for (size_t i = 0; i < n; i++) + s2[i] = c; + return s; +} + + +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, + .base_low = 0, + .base_high = 0, + + .ring = ring, + .code = code, + + .accessed = 0, + .rw = 1, + .conforming = 0, + .codeordata = 1, + .present = 1, + .long_mode = 1, + .available = 1, + .x32 = 0, + }; +} + +void gdt_init(void) { + GDT[SEG_null].present = 0; + + 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); + + lgdt_arg.limit = sizeof(GDT) - 1; + lgdt_arg.base = (uint64_t) &GDT; + + + memset32(&TSS, 0, sizeof(TSS)); + for (int i = 0; i < 3; i++) + TSS.rsp[i] = (uint64_t) &_isr_mini_stack; + TSS.ist[1] = (uint64_t) &_isr_mini_stack; + + uint64_t tss_addr = (uint64_t) &TSS; + GDT[SEG_TSS] = (struct gdt_entry) { + .limit_low = sizeof(TSS), + .limit_high = sizeof(TSS) >> 16, + .gran = 0, + .base_low = tss_addr, + .base_high = tss_addr >> 24, + + .accessed = 1, + .rw = 0, + .conforming = 0, + .code = 1, + .codeordata = 0, + .ring = 0, // was 3 pre-port + .present = 1, + .available = 1, + .long_mode = 0, + .x32 = 0, + }; + *((uint64_t*)&GDT[SEG_TSS2]) = (tss_addr >> 32); +} |