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

using seg = GDT::SegmentDescriptor;

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

constexpr uint32_t null_sz = 0;
constexpr uint32_t kseg_sz = 64 * 1024 * 1024 + 0xfff;

static GDT::SegmentDescriptor segments[256]{
    [GDT::null0] = seg::make<null_sz>(0, {}),
    [GDT::kcode] = seg::make<kseg_sz>(0, {.r_w = true, .exe = true, .segment = true, .present = true}),
    [GDT::kdata] = seg::make<kseg_sz>(0, {.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));
}