summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/hal/gdt.c
blob: 8bfe942012bef6689030afe9d9e4c19f1f0843ab (plain) (blame)
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
82
83
84
#include "gdt.h"
#include "smp.h"
#include "lib/string.h"

static struct gdt_entry _gdt[GDT_TSS_HI+1] = 
{
    [GDT_KERNEL_NULL] = { 0 },
    [GDT_KERNEL_CODE] = (struct gdt_entry) {
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0x0,
        .base_16_23 = 0x0,
        .type_flg = 0b10011010,
        .limit_flg = 0b10101111,
        .base_24_31 = 0x0
    },
    [GDT_KERNEL_DATA] = (struct gdt_entry) {
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0x0,
        .base_16_23 = 0x0,
        .type_flg = 0b10010010,
        .limit_flg = 0b10101111,
        .base_24_31 = 0x0
    },
    [GDT_USER_NULL] = { 0 },
    [GDT_USER_DATA] = (struct gdt_entry) {
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0x0,
        .base_16_23 = 0x0,
        .type_flg = 0b11110010,
        .limit_flg = 0b10101111,
        .base_24_31 = 0x0
    },
    [GDT_USER_CODE] = (struct gdt_entry) {
        .limit_0_15 = 0xFFFF,
        .base_0_15 = 0x0,
        .base_16_23 = 0x0,
        .type_flg = 0b11111010,
        .limit_flg = 0b10101111,
        .base_24_31 = 0x0
    },
    [GDT_TSS_LO] = (struct gdt_entry) {
        .limit_0_15 = 0x0,
        .base_0_15 = 0x0,
        .base_16_23 = 0x0,
        .type_flg = 0x89,
        .limit_flg = 0x0,
        .base_24_31 = 0x0       
    },
    [GDT_TSS_HI] = { 0 }
};

void
gdt_setup(processor_t *processor)
{
    memcpy(processor->gdt, _gdt, sizeof(struct gdt_entry) * (GDT_TSS_HI+1));
    memset(processor->iopb, 0, 0x2000);

    struct gdt_descriptor gdtr;
    gdtr.base = (uintptr_t)&processor->gdt;
    gdtr.limit = sizeof(struct gdt_entry) * (GDT_TSS_HI+1) - 1;

    extern void load_gdt(struct gdt_descriptor *gdtr);
    load_gdt(&gdtr);

    uintptr_t tss_base = (uintptr_t)&processor->tss;
    size_t tss_limit = sizeof(struct tss) + 0x2000;

    struct gdt_entry *tss_lo = &processor->gdt[GDT_TSS_LO];
    struct gdt_entry *tss_hi = &processor->gdt[GDT_TSS_HI];

    tss_lo->base_0_15 = (uint16_t)(tss_base & 0xFFFF);
    tss_lo->base_16_23 = (uint8_t)((tss_base >> 16) & 0xFF);
    tss_lo->base_24_31 = (uint8_t)((tss_base >> 24) & 0xFF);
    tss_hi->limit_0_15 = (uint16_t)((tss_base >> 32) & 0xFFFF);
    tss_hi->base_0_15 = (uint16_t)((tss_base >> 48) & 0xFFFF);

    tss_lo->limit_0_15 = (uint16_t)(tss_limit & 0xFFFF);
    tss_lo->limit_flg |= (uint8_t)((tss_limit >> 16) & 0xF);

    processor->tss.iopb = sizeof(struct tss);

    extern void load_tss(void);
    load_tss();
}