summaryrefslogtreecommitdiff
path: root/kernel/GDT.c
blob: 4bc7ca27c78c1953ac7155749aa6136a733caf8e (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
129
130
131
132
133
134
135
136
// http://wiki.osdev.org/GDT_Tutorial
#include "lib/logger/log.h"
#include "usermode.h"
#define FOOLOS_MODULE_NAME "GDT"

#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_setup()
{
    log(FOOLOS_MODULE_NAME,FOOLOS_LOG_INFO,"setting up Global Descriptor Table");
    //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);


}