aboutsummaryrefslogtreecommitdiff
path: root/src/gdt.cc
blob: 726a7d7edb9bbc1410a2be4c79cf014ec133e3e3 (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
#include "gdt.h"
#include <stdlib.h>

using seg = GDT::SegmentDescriptor;

static_assert(sizeof(GDT::Pointer) == 6);

constexpr uint32_t null_sz = 0;

/* TODO kcode should only contain the .text segment
 * TODO kdata should contain the other segments
 * */
constexpr uint32_t kseg_start = 0;
constexpr uint32_t kseg_sz = 0xffffffff;

__attribute__((section(".constinit"))) static GDT::SegmentDescriptor segments[256]{
    seg::make<null_sz>(0, {}),
    seg::make<kseg_sz>(kseg_start, {.r_w = true, .exe = true, .segment = true, .present = true}),
    seg::make<kseg_sz>(kseg_start, {.r_w = true, .segment = true, .present = true}),
};

GDT::GDT() {
  Pointer gdtr{.limit = sizeof(segments) - 1, .base = reinterpret_cast<uint32_t>(segments)};
  asm volatile("lgdt %0" : : "p"(gdtr));

  // flush the segment registers
  constexpr auto cs = GDT::descriptor(kcode);
  constexpr auto ds = GDT::descriptor(kdata);

  asm volatile(
      "jmpl %0,$.reload_cs\n\t"  // far jump: cs,location
      ".reload_cs:\n\t"
      "  mov %1, %%ds\n\t"  // ds
      "  mov %1, %%es\n\t"
      "  mov %1, %%fs\n\t"
      "  mov %1, %%gs\n\t"
      "  mov %1, %%ss\n\t" ::"i"(cs),
      "rm"(ds));

  printk("GDT installed at ", uhex{gdtr.base}, '\n');
}