aboutsummaryrefslogtreecommitdiff
path: root/src/gdt.cc
blob: 7b5e3dfb83cf637c31609c81f252e7c7004337d6 (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
#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]{
    [GDT::null0] = seg::make<null_sz>(0, {}),
    [GDT::kcode] = seg::make<kseg_sz>(kseg_start, {.r_w = true, .exe = true, .segment = true, .present = true}),
    [GDT::kdata] = 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
  const auto cs = descriptor(kcode);
  const auto ds = descriptor(kdata);

  asm volatile(
      "jmp %0,$.reload_cs\n\t"  // far jump takes cs
      ".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),
      "r"(ds));

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

uint16_t GDT::descriptor(GDT::SegmentMap i) const {
  return static_cast<uint16_t>(reinterpret_cast<const uint32_t>(&segments[i]) -
                               reinterpret_cast<const uint32_t>(&segments));
}