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

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

Do not align ia32 int handlers on any pre-defined power-of-two boundary but
rather define each one as a separate procedure with its own global label. The
label is used to populate the IDT and it also helps to maintain consistency
between C and assembly.

The old way was very error-prone because one did not get a warning when a
handler exceeded the size limit given by the alignment, which usually resulted
in very weird crashes.

In principle, the old way was also rather wasteful as the handler had to be
aligned on a power-of-two address. With the int handler size around 160 bytes,
the bytes 160 - 255 in each handler were simply wasted. In practice, however,
the image.iso size did not change (I'd expect it to drop by around 8K).

The old way did not detect a mistmatch between the C code idea of how many IDT
entries there are and the assembly language code idea of the same thing. It was
possible to initialize an IDT entry to point to some garbage and nobody would
notice until the int occurred.

The new method was a bit tiresome to write as there was a lot of copy'n'paste.
But since it was a one-time effort, I lumped it. If you know of a way to write a
for-loop in C preprocessor or use GAS assmebler macros in a sensible way, I will
gladly use your improvement.

  • Property mode set to 100644
File size: 8.6 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/slab.h>
44#include <memstr.h>
45#include <arch/boot/boot.h>
46#include <interrupt.h>
47
48/*
49 * Early ia32 configuration functions and data structures.
50 */
51
52/*
53 * We have no use for segmentation so we set up flat mode. In this
54 * mode, we use, for each privilege level, two segments spanning the
55 * whole memory. One is for code and one is for data.
56 *
57 * One is for GS register which holds pointer to the TLS thread
58 * structure in it's base.
59 */
60descriptor_t gdt[GDT_ITEMS] = {
61 /* NULL descriptor */
62 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
63 /* KTEXT descriptor */
64 { 0xffff, 0, 0, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 1, 1, 0 },
65 /* KDATA descriptor */
66 { 0xffff, 0, 0, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_KERNEL, 0xf, 0, 0, 1, 1, 0 },
67 /* UTEXT descriptor */
68 { 0xffff, 0, 0, AR_PRESENT | AR_CODE | DPL_USER, 0xf, 0, 0, 1, 1, 0 },
69 /* UDATA descriptor */
70 { 0xffff, 0, 0, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER, 0xf, 0, 0, 1, 1, 0 },
71 /* TSS descriptor - set up will be completed later */
72 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
73 /* TLS descriptor */
74 { 0xffff, 0, 0, AR_PRESENT | AR_DATA | AR_WRITABLE | DPL_USER, 0xf, 0, 0, 1, 1, 0 },
75 /* VESA Init descriptor */
76#ifdef CONFIG_FB
77 { 0xffff, 0, VESA_INIT_SEGMENT>>12, AR_PRESENT | AR_CODE | DPL_KERNEL, 0xf, 0, 0, 0, 0, 0 }
78#endif
79};
80
81static idescriptor_t idt[IDT_ITEMS];
82
83static tss_t tss;
84
85tss_t *tss_p = NULL;
86
87/* gdtr is changed by kmp before next CPU is initialized */
88ptr_16_32_t bootstrap_gdtr = { .limit = sizeof(gdt), .base = KA2PA((uintptr_t) gdt) };
89ptr_16_32_t gdtr = { .limit = sizeof(gdt), .base = (uintptr_t) gdt };
90
91void gdt_setbase(descriptor_t *d, uintptr_t base)
92{
93 d->base_0_15 = base & 0xffff;
94 d->base_16_23 = ((base) >> 16) & 0xff;
95 d->base_24_31 = ((base) >> 24) & 0xff;
96}
97
98void gdt_setlimit(descriptor_t *d, uint32_t limit)
99{
100 d->limit_0_15 = limit & 0xffff;
101 d->limit_16_19 = (limit >> 16) & 0xf;
102}
103
104void idt_setoffset(idescriptor_t *d, uintptr_t offset)
105{
106 /*
107 * Offset is a linear address.
108 */
109 d->offset_0_15 = offset & 0xffff;
110 d->offset_16_31 = offset >> 16;
111}
112
113void tss_initialize(tss_t *t)
114{
115 memsetb(t, sizeof(tss_t), 0);
116}
117
118/*
119 * This function takes care of proper setup of IDT and IDTR.
120 */
121void idt_init(void)
122{
123 idescriptor_t *d;
124 unsigned int i;
125
126 for (i = 0; i < IDT_ITEMS; i++) {
127 d = &idt[i];
128
129 d->unused = 0;
130 d->selector = gdtselector(KTEXT_DES);
131
132 d->access = AR_PRESENT | AR_INTERRUPT; /* masking interrupt */
133
134 if (i == VECTOR_SYSCALL) {
135 /*
136 * The syscall interrupt gate must be calleable from
137 * userland.
138 */
139 d->access |= DPL_USER;
140 }
141 }
142
143 d = &idt[0];
144 idt_setoffset(d++, (uintptr_t) &int_0);
145 idt_setoffset(d++, (uintptr_t) &int_1);
146 idt_setoffset(d++, (uintptr_t) &int_2);
147 idt_setoffset(d++, (uintptr_t) &int_3);
148 idt_setoffset(d++, (uintptr_t) &int_4);
149 idt_setoffset(d++, (uintptr_t) &int_5);
150 idt_setoffset(d++, (uintptr_t) &int_6);
151 idt_setoffset(d++, (uintptr_t) &int_7);
152 idt_setoffset(d++, (uintptr_t) &int_8);
153 idt_setoffset(d++, (uintptr_t) &int_9);
154 idt_setoffset(d++, (uintptr_t) &int_10);
155 idt_setoffset(d++, (uintptr_t) &int_11);
156 idt_setoffset(d++, (uintptr_t) &int_12);
157 idt_setoffset(d++, (uintptr_t) &int_13);
158 idt_setoffset(d++, (uintptr_t) &int_14);
159 idt_setoffset(d++, (uintptr_t) &int_15);
160 idt_setoffset(d++, (uintptr_t) &int_16);
161 idt_setoffset(d++, (uintptr_t) &int_17);
162 idt_setoffset(d++, (uintptr_t) &int_18);
163 idt_setoffset(d++, (uintptr_t) &int_19);
164 idt_setoffset(d++, (uintptr_t) &int_20);
165 idt_setoffset(d++, (uintptr_t) &int_21);
166 idt_setoffset(d++, (uintptr_t) &int_22);
167 idt_setoffset(d++, (uintptr_t) &int_23);
168 idt_setoffset(d++, (uintptr_t) &int_24);
169 idt_setoffset(d++, (uintptr_t) &int_25);
170 idt_setoffset(d++, (uintptr_t) &int_26);
171 idt_setoffset(d++, (uintptr_t) &int_27);
172 idt_setoffset(d++, (uintptr_t) &int_28);
173 idt_setoffset(d++, (uintptr_t) &int_29);
174 idt_setoffset(d++, (uintptr_t) &int_30);
175 idt_setoffset(d++, (uintptr_t) &int_31);
176 idt_setoffset(d++, (uintptr_t) &int_32);
177 idt_setoffset(d++, (uintptr_t) &int_33);
178 idt_setoffset(d++, (uintptr_t) &int_34);
179 idt_setoffset(d++, (uintptr_t) &int_35);
180 idt_setoffset(d++, (uintptr_t) &int_36);
181 idt_setoffset(d++, (uintptr_t) &int_37);
182 idt_setoffset(d++, (uintptr_t) &int_38);
183 idt_setoffset(d++, (uintptr_t) &int_39);
184 idt_setoffset(d++, (uintptr_t) &int_40);
185 idt_setoffset(d++, (uintptr_t) &int_41);
186 idt_setoffset(d++, (uintptr_t) &int_42);
187 idt_setoffset(d++, (uintptr_t) &int_43);
188 idt_setoffset(d++, (uintptr_t) &int_44);
189 idt_setoffset(d++, (uintptr_t) &int_45);
190 idt_setoffset(d++, (uintptr_t) &int_46);
191 idt_setoffset(d++, (uintptr_t) &int_47);
192 idt_setoffset(d++, (uintptr_t) &int_48);
193 idt_setoffset(d++, (uintptr_t) &int_49);
194 idt_setoffset(d++, (uintptr_t) &int_50);
195 idt_setoffset(d++, (uintptr_t) &int_51);
196 idt_setoffset(d++, (uintptr_t) &int_52);
197 idt_setoffset(d++, (uintptr_t) &int_53);
198 idt_setoffset(d++, (uintptr_t) &int_54);
199 idt_setoffset(d++, (uintptr_t) &int_55);
200 idt_setoffset(d++, (uintptr_t) &int_56);
201 idt_setoffset(d++, (uintptr_t) &int_57);
202 idt_setoffset(d++, (uintptr_t) &int_58);
203 idt_setoffset(d++, (uintptr_t) &int_59);
204 idt_setoffset(d++, (uintptr_t) &int_60);
205 idt_setoffset(d++, (uintptr_t) &int_61);
206 idt_setoffset(d++, (uintptr_t) &int_62);
207 idt_setoffset(d++, (uintptr_t) &int_63);
208}
209
210/* Clean IOPL(12,13) and NT(14) flags in EFLAGS register */
211static void clean_IOPL_NT_flags(void)
212{
213 asm volatile (
214 "pushfl\n"
215 "pop %%eax\n"
216 "and $0xffff8fff, %%eax\n"
217 "push %%eax\n"
218 "popfl\n"
219 ::: "eax"
220 );
221}
222
223/* Clean AM(18) flag in CR0 register */
224static void clean_AM_flag(void)
225{
226 asm volatile (
227 "mov %%cr0, %%eax\n"
228 "and $0xfffbffff, %%eax\n"
229 "mov %%eax, %%cr0\n"
230 ::: "eax"
231 );
232}
233
234void pm_init(void)
235{
236 descriptor_t *gdt_p = (descriptor_t *) gdtr.base;
237 ptr_16_32_t idtr;
238
239 /*
240 * Update addresses in GDT and IDT to their virtual counterparts.
241 */
242 idtr.limit = sizeof(idt);
243 idtr.base = (uintptr_t) idt;
244 gdtr_load(&gdtr);
245 idtr_load(&idtr);
246
247 /*
248 * Each CPU has its private GDT and TSS.
249 * All CPUs share one IDT.
250 */
251
252 if (config.cpu_active == 1) {
253 idt_init();
254 /*
255 * NOTE: bootstrap CPU has statically allocated TSS, because
256 * the heap hasn't been initialized so far.
257 */
258 tss_p = &tss;
259 }
260 else {
261 tss_p = (tss_t *) malloc(sizeof(tss_t), FRAME_ATOMIC);
262 if (!tss_p)
263 panic("Cannot allocate TSS.");
264 }
265
266 tss_initialize(tss_p);
267
268 gdt_p[TSS_DES].access = AR_PRESENT | AR_TSS | DPL_KERNEL;
269 gdt_p[TSS_DES].special = 1;
270 gdt_p[TSS_DES].granularity = 0;
271
272 gdt_setbase(&gdt_p[TSS_DES], (uintptr_t) tss_p);
273 gdt_setlimit(&gdt_p[TSS_DES], TSS_BASIC_SIZE - 1);
274
275 /*
276 * As of this moment, the current CPU has its own GDT pointing
277 * to its own TSS. We just need to load the TR register.
278 */
279 tr_load(gdtselector(TSS_DES));
280
281 clean_IOPL_NT_flags(); /* Disable I/O on nonprivileged levels and clear NT flag. */
282 clean_AM_flag(); /* Disable alignment check */
283}
284
285void set_tls_desc(uintptr_t tls)
286{
287 ptr_16_32_t cpugdtr;
288 descriptor_t *gdt_p;
289
290 gdtr_store(&cpugdtr);
291 gdt_p = (descriptor_t *) cpugdtr.base;
292 gdt_setbase(&gdt_p[TLS_DES], tls);
293 /* Reload gdt register to update GS in CPU */
294 gdtr_load(&cpugdtr);
295}
296
297/** @}
298 */
Note: See TracBrowser for help on using the repository browser.