aboutsummaryrefslogtreecommitdiffstats
path: root/gdt.cpp
blob: 27b9f4215487159e3e55c485902ac8d3d33b5d8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <array>
#include <cstdint>

struct gdt_entry_bits {
    std::uint32_t limit_low              : 16;
    std::uint32_t base_low               : 24;
    std::uint32_t accessed               :  1;
    std::uint32_t read_write             :  1; // readable for code, writable for data
    std::uint32_t conforming_expand_down :  1; // conforming for code, expand down for data
    std::uint32_t code                   :  1; // 1 for code, 0 for data
    std::uint32_t code_data_segment      :  1; // should be 1 for everything but TSS and LDT
    std::uint32_t DPL                    :  2; // privilege level
    std::uint32_t present                :  1;
    std::uint32_t limit_high             :  4;
    std::uint32_t available              :  1; // only used in software; has no effect on hardware
    std::uint32_t long_mode              :  1;
    std::uint32_t big                    :  1; // 32-bit opcodes for code, uint32_t stack for data
    std::uint32_t gran                   :  1; // 1 to use 4k page addressing, 0 for byte addressing
    std::uint32_t base_high              :  8;
} __attribute__((packed));

constinit static const std::array<gdt_entry_bits, 3> gdt {{
    {},
    /* kernel_code = */ {
        .limit_low = 0xFFFF,
        .base_low = 0x0000,
        .accessed = 0,
        .read_write = 1,
        .conforming_expand_down = 0,
        .code = 1,
        .code_data_segment = 1,
        .DPL = 0,
        .present = 1,
        .limit_high = 0xF,
        .available = 0,
        .long_mode = 0,
        .big = 1,
        .gran = 1,
        .base_high = 0x00
    },
    /* kernel_data = */ {
        .limit_low = 0xFFFF,
        .base_low = 0x0000,
        .accessed = 0,
        .read_write = 1,
        .conforming_expand_down = 0,
        .code = 0,
        .code_data_segment = 1,
        .DPL = 0,
        .present = 1,
        .limit_high = 0xF,
        .available = 0,
        .long_mode = 0,
        .big = 1,
        .gran = 1,
        .base_high = 0x00
    }
}};

void gdt_initialize()
{
    auto gdtr = reinterpret_cast<std::uint64_t>(gdt.data());
    gdtr <<= 16;
    gdtr |= gdt.size() * sizeof(gdt[0]);

    asm volatile(R"(
        lgdt %0
        pushl $0x8
        push $.setcs
        ljmp *(%%esp)
    .setcs:
        add $8, %%esp
        mov $0x10, %%eax
        mov %%eax, %%ds
        mov %%eax, %%es
        mov %%eax, %%fs
        mov %%eax, %%gs
        mov %%eax, %%ss
    )" :: "m"(gdtr));
}