summaryrefslogtreecommitdiff
path: root/kernel/cpu/gdt.c
blob: d91abed5da86cde2017a2d44e4ebac4496056bf9 (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
#include "gdt.h"
#include <cpu/arch_inst.h>
#include <interrupts.h>

extern void flush_tss(void);
extern void load_gdt(void *);

typedef struct tss_entry_struct tss_entry_t;

tss_entry_t tss_entry;

typedef union {
  struct GDT_Entry s;
  u64 raw;
} GDT_Entry;

GDT_Entry gdt_entries[6] = {0};
GDT_Pointer gdtr;

extern u32 inital_esp;
void write_tss(struct GDT_Entry *gdt_entry) {
  u32 base = (u32)&tss_entry;
  u32 limit = sizeof(tss_entry);

  gdt_entry->limit_low = limit;
  gdt_entry->base_low = base;
  gdt_entry->accessed = 1;
  gdt_entry->read_write = 0;
  gdt_entry->conforming_expand_down = 0;
  gdt_entry->code = 1;
  gdt_entry->code_data_segment = 0;
  gdt_entry->DPL = 0;
  gdt_entry->present = 1;
  gdt_entry->limit_high = limit >> 16;
  gdt_entry->available = 0;
  gdt_entry->long_mode = 0;
  gdt_entry->big = 0;
  gdt_entry->gran = 0;
  gdt_entry->base_high = (base & ((u32)0xff << 24)) >> 24;

  memset(&tss_entry, 0, sizeof tss_entry);
  tss_entry.ss0 = GDT_KERNEL_DATA_SEGMENT * GDT_ENTRY_SIZE;
  tss_entry.esp0 = get_current_sp();
}

void gdt_init() {
  gdt_entries[GDT_NULL_SEGMENT].raw = 0x0;
  gdt_entries[GDT_KERNEL_CODE_SEGMENT].raw =
      0xCF9A000000FFFF; // Kernel code segment
  gdt_entries[GDT_KERNEL_DATA_SEGMENT].raw =
      0xCF92000000FFFF; // Kernel data segment

  // Usermode code segment
  memcpy(&gdt_entries[GDT_USERMODE_CODE_SEGMENT],
         &gdt_entries[GDT_KERNEL_CODE_SEGMENT], GDT_ENTRY_SIZE);

  // Usermode data segment
  memcpy(&gdt_entries[GDT_USERMODE_DATA_SEGMENT],
         &gdt_entries[GDT_KERNEL_DATA_SEGMENT], GDT_ENTRY_SIZE);

  // Set DPL to 3 to indicate that the segment is in ring 3
  gdt_entries[GDT_USERMODE_CODE_SEGMENT].s.DPL = 3;
  gdt_entries[GDT_USERMODE_DATA_SEGMENT].s.DPL = 3;

  write_tss((struct GDT_Entry *)&gdt_entries[GDT_TSS_SEGMENT]);

  gdtr.offset = (u32)&gdt_entries;
  gdtr.size = sizeof(gdt_entries) - 1;

  disable_interrupts();
  load_gdt(&gdtr);
  flush_tss();
}