source: mainline/kernel/arch/ia32/src/pm.c@ 4b0206c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4b0206c was 650cd22, checked in by Jakub Jermar <jakub@…>, 9 years ago

Use designated initializer for initializing GDT

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ia32
30 * @{
31 */
32/** @file
33 */
34
35#include <arch/pm.h>
36#include <config.h>
37#include <typedefs.h>
38#include <arch/interrupt.h>
39#include <arch/asm.h>
40#include <arch/context.h>
41#include <panic.h>
42#include <arch/mm/page.h>
43#include <mm/km.h>
44#include <mm/frame.h>
45#include <mm/slab.h>
46#include <memstr.h>
47#include <arch/boot/boot.h>
48#include <interrupt.h>
49
50/*
51 * Early ia32 configuration functions and data structures.
52 */
53
54/*
55 * We don't have much use for segmentation so we set up flat mode.
56 * In this mode, we use, for each privilege level, two segments spanning the
57 * whole memory. One is for code and one is for data.
58 *
59 * One special segment apart of that is for the GS register which holds
60 * a pointer to the VREG page in its base.
61 */
62descriptor_t gdt[GDT_ITEMS] = {
63 [NULL_DES] = {
64 0
65 },
66 [KTEXT_DES] = {
67 .limit_0_15 = 0xffff,
68 .limit_16_19 = 0xf,
69 .access = AR_PRESENT | AR_CODE | DPL_KERNEL,
70 .special = 1,
71 .granularity = 1
72 },
73 [KDATA_DES] = {
74 .limit_0_15 = 0xffff,
75 .limit_16_19 = 0xf,
76 .access = AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_KERNEL,
77 .special = 1,
78 .granularity = 1
79 },
80 [UTEXT_DES] = {
81 .limit_0_15 = 0xffff,
82 .limit_16_19 = 0xf,
83 .access = AR_PRESENT | AR_CODE | DPL_USER,
84 .special = 1,
85 .granularity = 1
86 },
87 [UDATA_DES] = {
88 .limit_0_15 = 0xffff,
89 .limit_16_19 = 0xf,
90 .access = AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER,
91 .special = 1,
92 .granularity = 1
93 },
94 [TSS_DES] = { /* set up will be completed later */
95 0,
96 },
97 [VREG_DES] = { /* will be reinitialized later */
98 .limit_0_15 = 0xffff,
99 .limit_16_19 = 0xf,
100 .access = AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER,
101 .special = 1,
102 .granularity = 1
103 },
104 /* VESA Init descriptor */
105#ifdef CONFIG_FB
106 [VESA_INIT_CODE_DES] = {
107 .limit_0_15 = 0xffff,
108 .limit_16_19 = 0xf,
109 .base_16_23 = VESA_INIT_SEGMENT >> 12,
110 .access = AR_PRESENT | AR_CODE | AR_READABLE | DPL_KERNEL
111 },
112 [VESA_INIT_DATA_DES] = {
113 .limit_0_15 = 0xffff,
114 .limit_16_19 = 0xf,
115 .base_16_23 = VESA_INIT_SEGMENT >> 12,
116 .access = AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_KERNEL
117 }
118#endif
119};
120
121static idescriptor_t idt[IDT_ITEMS];
122
123static tss_t tss0;
124
125tss_t *tss_p = NULL;
126
127/* gdtr is changed by kmp before next CPU is initialized */
128ptr_16_32_t gdtr = {
129 .limit = sizeof(gdt),
130 .base = (uintptr_t) gdt
131};
132
133void gdt_setbase(descriptor_t *d, uintptr_t base)
134{
135 d->base_0_15 = base & 0xffff;
136 d->base_16_23 = (base >> 16) & 0xff;
137 d->base_24_31 = (base >> 24) & 0xff;
138}
139
140void gdt_setlimit(descriptor_t *d, uint32_t limit)
141{
142 d->limit_0_15 = limit & 0xffff;
143 d->limit_16_19 = (limit >> 16) & 0xf;
144}
145
146void idt_setoffset(idescriptor_t *d, uintptr_t offset)
147{
148 /*
149 * Offset is a linear address.
150 */
151 d->offset_0_15 = offset & 0xffff;
152 d->offset_16_31 = offset >> 16;
153}
154
155void tss_initialize(tss_t *t)
156{
157 memsetb(t, sizeof(tss_t), 0);
158}
159
160/*
161 * This function takes care of proper setup of IDT and IDTR.
162 */
163void idt_init(void)
164{
165 idescriptor_t *d;
166 unsigned int i;
167
168 for (i = 0; i < IDT_ITEMS; i++) {
169 d = &idt[i];
170
171 d->unused = 0;
172 d->selector = GDT_SELECTOR(KTEXT_DES);
173
174 if (i == VECTOR_SYSCALL) {
175 /*
176 * The syscall trap gate must be callable from
177 * userland. Interrupts will remain enabled.
178 */
179 d->access = AR_PRESENT | AR_TRAP | DPL_USER;
180 } else {
181 /*
182 * Other interrupts use interrupt gates which
183 * disable interrupts.
184 */
185 d->access = AR_PRESENT | AR_INTERRUPT;
186 }
187 }
188
189 d = &idt[0];
190 idt_setoffset(d++, (uintptr_t) &int_0);
191 idt_setoffset(d++, (uintptr_t) &int_1);
192 idt_setoffset(d++, (uintptr_t) &int_2);
193 idt_setoffset(d++, (uintptr_t) &int_3);
194 idt_setoffset(d++, (uintptr_t) &int_4);
195 idt_setoffset(d++, (uintptr_t) &int_5);
196 idt_setoffset(d++, (uintptr_t) &int_6);
197 idt_setoffset(d++, (uintptr_t) &int_7);
198 idt_setoffset(d++, (uintptr_t) &int_8);
199 idt_setoffset(d++, (uintptr_t) &int_9);
200 idt_setoffset(d++, (uintptr_t) &int_10);
201 idt_setoffset(d++, (uintptr_t) &int_11);
202 idt_setoffset(d++, (uintptr_t) &int_12);
203 idt_setoffset(d++, (uintptr_t) &int_13);
204 idt_setoffset(d++, (uintptr_t) &int_14);
205 idt_setoffset(d++, (uintptr_t) &int_15);
206 idt_setoffset(d++, (uintptr_t) &int_16);
207 idt_setoffset(d++, (uintptr_t) &int_17);
208 idt_setoffset(d++, (uintptr_t) &int_18);
209 idt_setoffset(d++, (uintptr_t) &int_19);
210 idt_setoffset(d++, (uintptr_t) &int_20);
211 idt_setoffset(d++, (uintptr_t) &int_21);
212 idt_setoffset(d++, (uintptr_t) &int_22);
213 idt_setoffset(d++, (uintptr_t) &int_23);
214 idt_setoffset(d++, (uintptr_t) &int_24);
215 idt_setoffset(d++, (uintptr_t) &int_25);
216 idt_setoffset(d++, (uintptr_t) &int_26);
217 idt_setoffset(d++, (uintptr_t) &int_27);
218 idt_setoffset(d++, (uintptr_t) &int_28);
219 idt_setoffset(d++, (uintptr_t) &int_29);
220 idt_setoffset(d++, (uintptr_t) &int_30);
221 idt_setoffset(d++, (uintptr_t) &int_31);
222 idt_setoffset(d++, (uintptr_t) &int_32);
223 idt_setoffset(d++, (uintptr_t) &int_33);
224 idt_setoffset(d++, (uintptr_t) &int_34);
225 idt_setoffset(d++, (uintptr_t) &int_35);
226 idt_setoffset(d++, (uintptr_t) &int_36);
227 idt_setoffset(d++, (uintptr_t) &int_37);
228 idt_setoffset(d++, (uintptr_t) &int_38);
229 idt_setoffset(d++, (uintptr_t) &int_39);
230 idt_setoffset(d++, (uintptr_t) &int_40);
231 idt_setoffset(d++, (uintptr_t) &int_41);
232 idt_setoffset(d++, (uintptr_t) &int_42);
233 idt_setoffset(d++, (uintptr_t) &int_43);
234 idt_setoffset(d++, (uintptr_t) &int_44);
235 idt_setoffset(d++, (uintptr_t) &int_45);
236 idt_setoffset(d++, (uintptr_t) &int_46);
237 idt_setoffset(d++, (uintptr_t) &int_47);
238 idt_setoffset(d++, (uintptr_t) &int_48);
239 idt_setoffset(d++, (uintptr_t) &int_49);
240 idt_setoffset(d++, (uintptr_t) &int_50);
241 idt_setoffset(d++, (uintptr_t) &int_51);
242 idt_setoffset(d++, (uintptr_t) &int_52);
243 idt_setoffset(d++, (uintptr_t) &int_53);
244 idt_setoffset(d++, (uintptr_t) &int_54);
245 idt_setoffset(d++, (uintptr_t) &int_55);
246 idt_setoffset(d++, (uintptr_t) &int_56);
247 idt_setoffset(d++, (uintptr_t) &int_57);
248 idt_setoffset(d++, (uintptr_t) &int_58);
249 idt_setoffset(d++, (uintptr_t) &int_59);
250 idt_setoffset(d++, (uintptr_t) &int_60);
251 idt_setoffset(d++, (uintptr_t) &int_61);
252 idt_setoffset(d++, (uintptr_t) &int_62);
253 idt_setoffset(d++, (uintptr_t) &int_63);
254
255 idt_setoffset(&idt[VECTOR_SYSCALL], (uintptr_t) &int_syscall);
256}
257
258/* Clean IOPL(12,13) and NT(14) flags in EFLAGS register */
259static void clean_IOPL_NT_flags(void)
260{
261 asm volatile (
262 "pushfl\n"
263 "pop %%eax\n"
264 "and $0xffff8fff, %%eax\n"
265 "push %%eax\n"
266 "popfl\n"
267 ::: "eax"
268 );
269}
270
271/* Clean AM(18) flag in CR0 register */
272static void clean_AM_flag(void)
273{
274 asm volatile (
275 "mov %%cr0, %%eax\n"
276 "and $0xfffbffff, %%eax\n"
277 "mov %%eax, %%cr0\n"
278 ::: "eax"
279 );
280}
281
282void pm_init(void)
283{
284 descriptor_t *gdt_p = (descriptor_t *) gdtr.base;
285 ptr_16_32_t idtr;
286
287 /*
288 * Update addresses in GDT and IDT to their virtual counterparts.
289 */
290 idtr.limit = sizeof(idt);
291 idtr.base = (uintptr_t) idt;
292 gdtr_load(&gdtr);
293 idtr_load(&idtr);
294
295 /*
296 * Each CPU has its private GDT and TSS.
297 * All CPUs share one IDT.
298 */
299
300 if (config.cpu_active == 1) {
301 idt_init();
302 /*
303 * NOTE: bootstrap CPU has statically allocated TSS, because
304 * the heap hasn't been initialized so far.
305 */
306 tss_p = &tss0;
307 } else {
308 tss_p = (tss_t *) malloc(sizeof(tss_t), FRAME_ATOMIC);
309 if (!tss_p)
310 panic("Cannot allocate TSS.");
311 }
312
313 tss_initialize(tss_p);
314
315 gdt_p[TSS_DES].access = AR_PRESENT | AR_TSS | DPL_KERNEL;
316 gdt_p[TSS_DES].special = 1;
317 gdt_p[TSS_DES].granularity = 0;
318
319 gdt_setbase(&gdt_p[TSS_DES], (uintptr_t) tss_p);
320 gdt_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE - 1);
321
322 /*
323 * As of this moment, the current CPU has its own GDT pointing
324 * to its own TSS. We just need to load the TR register.
325 */
326 tr_load(GDT_SELECTOR(TSS_DES));
327
328 clean_IOPL_NT_flags(); /* Disable I/O on nonprivileged levels and clear NT flag. */
329 clean_AM_flag(); /* Disable alignment check */
330}
331
332/** @}
333 */
Note: See TracBrowser for help on using the repository browser.