summaryrefslogtreecommitdiff
path: root/kernel/gdt.c
blob: 24b52f789a1524c4ad41689ab3f6b0b06e756771 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include "kernel.h"
#include "gdt.h"
#include "asm_gdt.h"
#include "kmalloc.h"

#include <stdint.h>

#define GDT_SIZE 6

static uint8_t gdt_structs[GDT_SIZE*8*SMP_MAX_PROC]; // GLOBAL DESCRIPTOR TABLES

typedef volatile struct strtss{
    unsigned short   link;
    unsigned short   link_h;  
    unsigned long   esp0;
    unsigned short   ss0;
    unsigned short   ss0_h;  
    unsigned long   esp1;
    unsigned short   ss1;
    unsigned short   ss1_h;  
    unsigned long   esp2;
    unsigned short   ss2;
    unsigned short   ss2_h;  
    unsigned long   cr3;
    unsigned long   eip;
    unsigned long   eflags;  
    unsigned long   eax;
    unsigned long   ecx; 
    unsigned long   edx;
    unsigned long    ebx;  
    unsigned long   esp;
    unsigned long   ebp;  
    unsigned long   esi;
    unsigned long   edi;  
    unsigned short   es;
    unsigned short   es_h;  
    unsigned short   cs;
    unsigned short   cs_h;  
    unsigned short   ss;
    unsigned short   ss_h;  
    unsigned short   ds;
    unsigned short   ds_h;  
    unsigned short   fs;
    unsigned short   fs_h;  
    unsigned short   gs;
    unsigned short   gs_h;  
    unsigned short   ldt;
    unsigned short   ldt_h;  
    unsigned short   trap;
    unsigned short   iomap;  
}__attribute__((packed)) tss_struct;  

tss_struct sys_tss[SMP_MAX_PROC]; 

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

void install_tss(uint32_t cpu,uint32_t esp0){

    // now fill each value
    // set values necessary
    sys_tss[cpu].ss0 = 0x10;            //kernel data
    sys_tss[cpu].esp0 = esp0;
    // now set the IO bitmap (not necessary, so set above limit)       
    // sys_tss.iomap = ( unsigned short ) sizeof( tss_struct ); 
}

/*
//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))
*/

void setup_gdt(uint8_t *gdt_struct)
{
    asm_setup_gdt(&gdt_struct[0],8*GDT_SIZE);
}

/**
 * \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)
    {
	kpanic("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()
{

    static int last_cpu=0;
    if(last_cpu>=SMP_MAX_PROC)kpanic("not enough SMP_MAX_PROC");
    
      /*
                            Pr=1 Privl 1    Exec DC   RW   Ac
      0x9A == 1001 1010  == 1    00    1    1    0    1    0
      0x92 == 1001 0010  == 1    00    1    0    0    1    0
      0xFA == 1111 1010  == 1    11    1    1    0    1    0
      0xF2 == 1111 0010  == 1    11    1    0    0    1    0
      */

    //static uint8_t gdt_struct[GDT_SIZE*8]; // GLOBAL DESCRIPTOR TABLE
    //uint8_t *gdt_struct=kballoc(1); //[GDT_SIZE*8]; // GLOBAL DESCRIPTOR TABLE
    uint8_t *gdt_struct=&gdt_structs[GDT_SIZE*8*last_cpu];
    GDT myGDT[GDT_SIZE];

    //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[last_cpu]; //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]);

    // update tss entry
    install_tss(last_cpu,0);
    last_cpu++;

    setup_gdt(gdt_struct);
}