summaryrefslogtreecommitdiff
path: root/kernel/gdt.c
blob: 46bf61a44a41d7c06e4cbf7b2d38e242f3f0b538 (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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// http://wiki.osdev.org/GDT_Tutorial

#include "usermode.h"

#include <stdint.h>
#define GDT_SIZE 6

extern sys_tss;

typedef struct GDT_struct
{
    uint32_t base;
    uint32_t limit;
    uint32_t type;

}GDT;

//alternative
struct gdt_entry_bits
{
	unsigned int limit_low:16;
	unsigned int base_low : 24;
     //attribute byte split into bitfields
	unsigned int accessed :1;
	unsigned int read_write :1; //readable for code, writable for data
	unsigned int conforming_expand_down :1; //conforming for code, expand down for data
	unsigned int code :1; //1 for code, 0 for data
	unsigned int always_1 :1; //should be 1 for everything but TSS and LDT
	unsigned int DPL :2; //priveledge level
	unsigned int present :1;
     //and now into granularity
	unsigned int limit_high :4;
	unsigned int available :1;
	unsigned int always_0 :1; //should always be 0
	unsigned int big :1; //32bit opcodes for code, uint32_t stack for data
	unsigned int gran :1; //1 to use 4k page addressing, 0 for byte addressing
	unsigned int base_high :8;
} __packed; //or __attribute__((packed))


static GDT myGDT[GDT_SIZE];
static uint8_t gdt_struct[GDT_SIZE*8];

/**
 * \param target A pointer to the 8-byte GDT entry
 * \param source An arbitrary structure describing the GDT entry
 */
void encodeGdtEntry(uint8_t *target, GDT source)
{
    // Check the limit to make sure that it can be encoded
    if ((source.limit > 65536) && (source.limit & 0xFFF) != 0xFFF)
    {
	panic(FOOLOS_MODULE_NAME,"trying to set an invalid GDT source.limit!");
    }
    if (source.limit > 65536) {
        // Adjust granularity if required
        source.limit = source.limit >> 12;
        target[6] = 0xC0;
    } else {
	target[6] = 0x40;
    }
 
    // Encode the limit
    target[0] = source.limit & 0xFF;
    target[1] = (source.limit >> 8) & 0xFF;
 
    // Encode the base 
    target[2] = source.base & 0xFF;
    target[3] = (source.base >> 8) & 0xFF;
    target[4] = (source.base >> 16) & 0xFF;
    target[7] = (source.base >> 24) & 0xFF;

    target[5] = source.type;
    target[6] |= (source.limit >> 16) & 0xF;
 
    // And... Type

    /*

0 1 dw 0xffff	    ;limit
2 3 dw 0x0	    ;base
4   db 0x0	    ;base
5   db 10011010b    ;flags
6   db 11001111b    ;flags & seg.limit
7   db 0x0	    ;base
    */
}

void gdt_init()
{
    //selector 0x0
    myGDT[0].base=0;
    myGDT[0].limit=0;
    myGDT[0].type=0;

    //selector 0x8 code
    myGDT[1].base=0;
    myGDT[1].limit=0xffffffff;
    myGDT[1].type=0x9a;

    //selector 0x10 data
    myGDT[2].base=0;
    myGDT[2].limit=0xffffffff;
    myGDT[2].type=0x92;

    //selector 0x18 code user
    myGDT[3].base=0;
    myGDT[3].limit=0xffffffff;
    myGDT[3].type=0xFa;

    //selector 0x20 data user
    myGDT[4].base=0;
    myGDT[4].limit=0xffffffff;
    myGDT[4].type=0xF2;

    //TSS 0x28
    myGDT[5].base=&sys_tss; //tss start?
    myGDT[5].limit=sizeof(tss_struct); //tss end?
    myGDT[5].type=0x89;

    // transcript to format the processor wants
    for(int i=0;i<GDT_SIZE;i++)
        encodeGdtEntry(&gdt_struct[8*i],myGDT[i]);

    // updat
    install_tss();
    setup_gdt(&gdt_struct[0],8*GDT_SIZE);
}