1#include <boot/gdt.h>
2#include <boot/tss.h>
3#include <console/panic.h>
4#include <console/printf.h>
5#include <mem/alloc.h>
6#include <mem/alloc_or_die.h>
7#include <mem/page.h>
8#include <stdint.h>
9#include <string.h>
10
11#define GDT_ENTRIES 7
12
13void gdt_set_tss(struct gdt_entry_tss *tss_desc, uint64_t base,
14 uint32_t limit) {
15 tss_desc->limit_low = limit & 0xFFFF;
16 tss_desc->base_low = base & 0xFFFF;
17 tss_desc->base_middle = (base >> 16) & 0xFF;
18 tss_desc->access = 0x89; // Present, type = 64-bit TSS (available)
19 tss_desc->granularity = (limit >> 16) & 0x0F;
20 tss_desc->granularity |= 0x00; // No granularity for TSS
21 tss_desc->base_high = (base >> 24) & 0xFF;
22 tss_desc->base_upper = (base >> 32) & 0xFFFFFFFF;
23 tss_desc->reserved = 0;
24}
25
26void gdt_set_gate(struct gdt_entry *gdt, int num, uint64_t base, uint32_t limit,
27 uint8_t access, uint8_t gran) {
28 gdt[num].limit_low = (limit & 0xFFFF);
29 gdt[num].base_low = (base & 0xFFFF);
30 gdt[num].base_middle = (base >> 16) & 0xFF;
31 gdt[num].access = access;
32 gdt[num].granularity = (limit >> 16) & 0x0F;
33 gdt[num].granularity |= (gran & 0xF0);
34 gdt[num].base_high = (base >> 24) & 0xFF;
35}
36
37void gdt_load(struct gdt_entry *gdt, uint64_t n_entries) {
38 struct gdt_ptr gp = {
39 .limit = (sizeof(struct gdt_entry) * n_entries) - 1,
40 .base = (uint64_t) gdt,
41 };
42 asm volatile("lgdt %0" : : "m"(gp));
43}
44
45void reload_segment_registers(uint16_t cs_selector, uint16_t ds_selector) {
46 asm volatile("pushq %0\n\t"
47 "leaq 1f(%%rip), %%rax\n\t"
48 "pushq %%rax\n\t"
49 "lretq\n\t"
50 "1:\n\t"
51 "movw %w1, %%ax\n\t"
52 "movw %%ax, %%ds\n\t"
53 "movw %%ax, %%es\n\t"
54 "movw %%ax, %%fs\n\t"
55 "movw %%ax, %%gs\n\t"
56 "movw %%ax, %%ss\n\t"
57 :
58 : "r"((uint64_t) cs_selector), "r"(ds_selector)
59 : "rax", "memory");
60}
61
62void gdt_init(struct gdt_entry *gdt, struct tss *tss) {
63 gdt_set_gate(gdt, num: 0, base: 0, limit: 0, access: 0, gran: 0); // Null
64
65 gdt_set_gate(gdt, num: 1, base: 0, limit: 0xFFFFFFFF, ACCESS_CODE_RING0, GRAN_CODE);
66 gdt_set_gate(gdt, num: 2, base: 0, limit: 0xFFFFFFFF, ACCESS_DATA_RING0, GRAN_DATA);
67 gdt_set_gate(gdt, num: 5, base: 0, limit: 0xFFFFFFFF, ACCESS_CODE_RING3, GRAN_CODE);
68 gdt_set_gate(gdt, num: 6, base: 0, limit: 0xFFFFFFFF, ACCESS_DATA_RING3, GRAN_DATA);
69
70 // TSS (occupies entries 3 and 4)
71 gdt_set_tss(tss_desc: (struct gdt_entry_tss *) &gdt[3], base: (uint64_t) tss,
72 limit: sizeof(struct tss) - 1);
73
74 tss->io_map_base = sizeof(struct tss);
75
76 gdt_load(gdt, GDT_ENTRIES);
77 tss->ist1 =
78 (uint64_t) alloc_or_die(kmalloc_aligned(8 * PAGE_SIZE, PAGE_SIZE));
79 tss->rsp0 =
80 (uint64_t) alloc_or_die(kmalloc_aligned(8 * PAGE_SIZE, PAGE_SIZE));
81
82 /* stacks grow down */
83 tss->ist1 += 8 * PAGE_SIZE;
84 tss->rsp0 += 8 * PAGE_SIZE;
85
86 reload_segment_registers(GDT_KERNEL_CODE, GDT_KERNEL_DATA);
87
88 asm volatile("ltr %w0" : : "r"(0x18)); // TSS selector
89}
90
91void gdt_install(void) {
92 struct gdt_entry *gdt = kmalloc_aligned(
93 sizeof(struct gdt_entry) * GDT_ENTRIES, 64, ALLOC_FLAGS_ZERO);
94 struct tss *tss = kmalloc_aligned(sizeof(struct tss), 64, ALLOC_FLAGS_ZERO);
95 if (!gdt || !tss)
96 panic("GDT INIT NOT OK!!!");
97
98 gdt_init(gdt, tss);
99
100 return;
101}
102