19
19
20
20
/* access */
21
21
# define GDT_ACCESS_SET 0x01
22
- # define GDT_ACCESS_RW 0x02
23
- # define GDT_ACCESS_X 0x08
22
+ # define GDT_ACCESS_PROT_RW 0x02
23
+ # define GDT_ACCESS_PROT_X 0x08
24
24
# define GDT_ACCESS_SEGMENT 0x10
25
25
# define GDT_ACCESS_RING (level ) ((level) << 5)
26
26
# define GDT_ACCESS_PRESENT 0x80
@@ -48,6 +48,21 @@ typedef struct _GDTEntry
48
48
} GDTEntry ;
49
49
#pragma pack()
50
50
51
+ #pragma pack(1)
52
+ typedef struct _LDT
53
+ {
54
+ uint8_t limit0 ;
55
+ uint8_t limit1 ;
56
+ uint8_t base0 ;
57
+ uint8_t base1 ;
58
+ uint8_t base2 ;
59
+ uint8_t access ;
60
+ unsigned int limit2 :4 ;
61
+ unsigned int flags :4 ;
62
+ uint8_t base3 ;
63
+ } LDT ;
64
+ #pragma pack()
65
+
51
66
struct _GDT
52
67
{
53
68
GDTEntry entries [GDT_ENTRIES_MAX ];
@@ -58,9 +73,13 @@ struct _GDT
58
73
/* prototypes */
59
74
extern void __arch_setgdt (GDTEntry const * entries , size_t count );
60
75
76
+ static int _gdt_append_entry (GDT * gdt , vaddr_t base , uint32_t limit ,
77
+ uint8_t access , uint8_t flags );
78
+
61
79
62
80
/* variables */
63
81
static GDT _gdt ;
82
+ static TSS _tss ;
64
83
65
84
66
85
/* functions */
@@ -74,17 +93,27 @@ GDT * gdt_init(void)
74
93
75
94
76
95
/* gdt_init_table */
77
- int gdt_init_table (GDTTable const * table , size_t count )
96
+ int gdt_init_table (GDTTable const * table , size_t table_cnt , size_t tss_cnt )
78
97
{
79
98
int ret = 0 ;
80
99
GDT * gdt ;
81
100
size_t i ;
82
101
83
102
gdt = gdt_init ();
84
- for (i = 0 ; i < count ; i ++ )
103
+ for (i = 0 ; i < table_cnt ; i ++ )
85
104
if ((ret = gdt_append (gdt , table [i ].base , table [i ].size ,
86
105
table [i ].prot )) != 0 )
87
106
return ret ;
107
+ /* set the TSS */
108
+ if (tss_cnt > 1 )
109
+ {
110
+ errno = ENOSYS ;
111
+ return -1 ;
112
+ }
113
+ else if (tss_cnt == 1 && (ret = gdt_append_system (gdt , & _tss ,
114
+ sizeof (_tss ), GDT_SYSTEM_TYPE_TSS ))
115
+ != 0 )
116
+ return ret ;
88
117
gdt_apply (gdt );
89
118
return 0 ;
90
119
}
@@ -94,10 +123,9 @@ int gdt_init_table(GDTTable const * table, size_t count)
94
123
/* gdt_append */
95
124
int gdt_append (GDT * gdt , vaddr_t base , size_t size , unsigned int prot )
96
125
{
97
- GDTEntry * entry ;
98
126
uint32_t limit ;
99
- uint8_t access = GDT_ACCESS_PRESENT
100
- | GDT_ACCESS_SEGMENT | GDT_ACCESS_RING (0 );
127
+ uint8_t access = GDT_ACCESS_SEGMENT | GDT_ACCESS_PRESENT
128
+ | GDT_ACCESS_RING (0 );
101
129
uint8_t flags = GDT_FLAG_PROTECTED_MODE ;
102
130
103
131
/* check for errors */
@@ -106,9 +134,7 @@ int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot)
106
134
errno = ERANGE ;
107
135
return -1 ;
108
136
}
109
- if (gdt -> entries_cnt >= sizeof (gdt -> entries ) / sizeof (* gdt -> entries )
110
- || size > ULONG_MAX
111
- || ULONG_MAX - size < base )
137
+ if (size > ULONG_MAX || ULONG_MAX - size < base )
112
138
{
113
139
errno = ENOMEM ;
114
140
return -1 ;
@@ -120,41 +146,72 @@ int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot)
120
146
errno = EPERM ;
121
147
return -1 ;
122
148
}
123
- entry = & gdt -> entries [gdt -> entries_cnt ];
124
- /* base */
125
- entry -> base0 = base & 0xff ;
126
- entry -> base1 = (base & 0xff00 ) >> 8 ;
127
- entry -> base2 = (base & 0xff0000 ) >> 16 ;
128
- entry -> base3 = (base & 0xff000000 ) >> 24 ;
129
149
/* limit */
130
150
if (size - 1 > GDT_LIMIT_MAX )
131
151
{
132
152
limit = (size & 0xfff ) == 0
133
- ? (size >> 12 )
134
- : (((size | 0xfff ) + 1 ) >> 12 );
135
- limit -- ;
153
+ ? (size >> 12 ) - 1
154
+ : (((size | 0xfff ) + 1 ) >> 12 ) - 1 ;
136
155
flags |= GDT_FLAG_PAGE_GRANULARITY ;
137
156
}
138
157
else
139
158
limit = size - 1 ;
140
- entry -> limit0 = limit & 0xff ;
141
- entry -> limit1 = (limit & 0xff00 ) >> 8 ;
142
- entry -> limit2 = (limit & 0xf0000 ) >> 16 ;
143
159
/* access */
144
160
if (prot == (PROT_READ | PROT_EXEC ))
145
161
/* code segment */
146
- access |= GDT_ACCESS_RW | GDT_ACCESS_X ;
162
+ access |= GDT_ACCESS_PROT_RW | GDT_ACCESS_PROT_X ;
147
163
else if (prot == (PROT_READ | PROT_WRITE ))
148
164
/* data segment (read/write) */
149
- access |= GDT_ACCESS_RW ;
165
+ access |= GDT_ACCESS_PROT_RW ;
150
166
else if (prot == PROT_READ )
151
167
/* data segment (read-only) */
152
168
access |= GDT_ACCESS_SET ;
153
- entry -> access = access ;
154
- /* flags */
155
- entry -> flags = flags ;
156
- gdt -> entries_cnt ++ ;
157
- return 0 ;
169
+ return _gdt_append_entry (gdt , base , limit , access , flags );
170
+ }
171
+
172
+
173
+ /* gdt_append_system */
174
+ static int _append_system_ldt (GDT * gdt , void * base , size_t size );
175
+ static int _append_system_tss (GDT * gdt , void * base , size_t size );
176
+
177
+ int gdt_append_system (GDT * gdt , void * base , size_t size , unsigned int type )
178
+ {
179
+ switch (type )
180
+ {
181
+ case GDT_SYSTEM_TYPE_LDT :
182
+ return _append_system_ldt (gdt , base , size );
183
+ case GDT_SYSTEM_TYPE_TSS :
184
+ return _append_system_tss (gdt , base , size );
185
+ default :
186
+ errno = ENOSYS ;
187
+ return -1 ;
188
+ }
189
+ }
190
+
191
+ static int _append_system_ldt (GDT * gdt , void * base , size_t size )
192
+ {
193
+ uint32_t access = GDT_ACCESS_PRESENT | GDT_SYSTEM_TYPE_LDT ;
194
+ uint8_t flags = GDT_FLAG_PROTECTED_MODE ;
195
+
196
+ if (size != sizeof (LDT ))
197
+ {
198
+ errno = ERANGE ;
199
+ return -1 ;
200
+ }
201
+ return _gdt_append_entry (gdt , (vaddr_t )base , size - 1 , access , flags );
202
+ }
203
+
204
+ static int _append_system_tss (GDT * gdt , void * base , size_t size )
205
+ {
206
+ uint32_t access = GDT_ACCESS_PRESENT | GDT_SYSTEM_TYPE_TSS ;
207
+ uint8_t flags = GDT_FLAG_PROTECTED_MODE ;
208
+
209
+ if (size != sizeof (TSS ))
210
+ {
211
+ errno = ERANGE ;
212
+ return -1 ;
213
+ }
214
+ return _gdt_append_entry (gdt , (vaddr_t )base , size - 1 , access , flags );
158
215
}
159
216
160
217
@@ -163,4 +220,32 @@ void gdt_apply(GDT * gdt)
163
220
{
164
221
__arch_setgdt (gdt -> entries , gdt -> entries_cnt );
165
222
}
223
+
224
+
225
+ /* private */
226
+ /* gdt_append_entry */
227
+ static int _gdt_append_entry (GDT * gdt , vaddr_t base , uint32_t limit ,
228
+ uint8_t access , uint8_t flags )
229
+ {
230
+ GDTEntry * entry ;
231
+
232
+ /* check for errors */
233
+ if (gdt -> entries_cnt >= sizeof (gdt -> entries ) / sizeof (* gdt -> entries ))
234
+ {
235
+ errno = ENOMEM ;
236
+ return -1 ;
237
+ }
238
+ entry = & gdt -> entries [gdt -> entries_cnt ];
239
+ entry -> base0 = base & 0xff ;
240
+ entry -> base1 = (base & 0xff00 ) >> 8 ;
241
+ entry -> base2 = (base & 0xff0000 ) >> 16 ;
242
+ entry -> base3 = (base & 0xff000000 ) >> 24 ;
243
+ entry -> limit0 = limit & 0xff ;
244
+ entry -> limit1 = (limit & 0xff00 ) >> 8 ;
245
+ entry -> limit2 = (limit & 0xf0000 ) >> 16 ;
246
+ entry -> access = access ;
247
+ entry -> flags = flags ;
248
+ gdt -> entries_cnt ++ ;
249
+ return 0 ;
250
+ }
166
251
#endif
0 commit comments