2 * Copyright (c) 2008 Jakub Jermar
3 * Copyright (c) 2005-2006 Ondrej Palkovsky
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 /** @addtogroup kernel_amd64
45 * There is no segmentation in long mode so we set up flat mode. In this
46 * mode, we use, for each privilege level, two segments spanning the
47 * whole memory. One is for code and one is for data.
50 descriptor_t gdt
[GDT_ITEMS
] = {
55 .limit_0_15
= 0xffffU
,
57 .access
= AR_PRESENT
| AR_CODE
| DPL_KERNEL
| AR_READABLE
,
62 .limit_0_15
= 0xffffU
,
64 .access
= AR_PRESENT
| AR_DATA
| AR_WRITABLE
| DPL_KERNEL
,
68 .limit_0_15
= 0xffffU
,
70 .access
= AR_PRESENT
| AR_DATA
| AR_WRITABLE
| DPL_USER
,
75 .limit_0_15
= 0xffffU
,
77 .access
= AR_PRESENT
| AR_CODE
| DPL_USER
,
82 .limit_0_15
= 0xffffU
,
84 .access
= AR_PRESENT
| AR_CODE
| DPL_KERNEL
| AR_READABLE
,
89 * TSS descriptor - set up will be completed later,
90 * on AMD64 it is 64-bit - 2 items in the table
98 /* VESA Init descriptor */
100 [VESA_INIT_CODE_DES
] = {
101 .limit_0_15
= 0xffff,
103 .base_16_23
= VESA_INIT_SEGMENT
>> 12,
104 .access
= AR_PRESENT
| AR_CODE
| AR_READABLE
| DPL_KERNEL
106 [VESA_INIT_DATA_DES
] = {
107 .limit_0_15
= 0xffff,
109 .base_16_23
= VESA_INIT_SEGMENT
>> 12,
110 .access
= AR_PRESENT
| AR_DATA
| AR_WRITABLE
| DPL_KERNEL
115 idescriptor_t idt
[IDT_ITEMS
];
118 .limit
= sizeof(gdt
),
119 .base
= (uint64_t) gdt
122 .limit
= sizeof(idt
),
123 .base
= (uint64_t) idt
129 void gdt_tss_setbase(descriptor_t
*d
, uintptr_t base
)
131 tss_descriptor_t
*td
= (tss_descriptor_t
*) d
;
133 td
->base_0_15
= base
& 0xffffU
;
134 td
->base_16_23
= ((base
) >> 16) & 0xffU
;
135 td
->base_24_31
= ((base
) >> 24) & 0xffU
;
136 td
->base_32_63
= ((base
) >> 32);
139 void gdt_tss_setlimit(descriptor_t
*d
, uint32_t limit
)
141 tss_descriptor_t
*td
= (tss_descriptor_t
*) d
;
143 td
->limit_0_15
= limit
& 0xffffU
;
144 td
->limit_16_19
= (limit
>> 16) & 0x0fU
;
147 void idt_setoffset(idescriptor_t
*d
, uintptr_t offset
)
150 * Offset is a linear address.
152 d
->offset_0_15
= offset
& 0xffffU
;
153 d
->offset_16_31
= (offset
>> 16) & 0xffffU
;
154 d
->offset_32_63
= offset
>> 32;
157 void tss_initialize(tss_t
*t
)
159 memsetb(t
, sizeof(tss_t
), 0);
163 * This function takes care of proper setup of IDT and IDTR.
169 for (unsigned i
= 0; i
< IDT_ITEMS
; i
++) {
173 d
->selector
= GDT_SELECTOR(KTEXT_DES
);
176 d
->type
= AR_INTERRUPT
; /* masking interrupt */
183 idt_setoffset(d
++, (uintptr_t) &int_0
);
184 idt_setoffset(d
++, (uintptr_t) &int_1
);
185 idt_setoffset(d
++, (uintptr_t) &int_2
);
186 idt_setoffset(d
++, (uintptr_t) &int_3
);
187 idt_setoffset(d
++, (uintptr_t) &int_4
);
188 idt_setoffset(d
++, (uintptr_t) &int_5
);
189 idt_setoffset(d
++, (uintptr_t) &int_6
);
190 idt_setoffset(d
++, (uintptr_t) &int_7
);
191 idt_setoffset(d
++, (uintptr_t) &int_8
);
192 idt_setoffset(d
++, (uintptr_t) &int_9
);
193 idt_setoffset(d
++, (uintptr_t) &int_10
);
194 idt_setoffset(d
++, (uintptr_t) &int_11
);
195 idt_setoffset(d
++, (uintptr_t) &int_12
);
196 idt_setoffset(d
++, (uintptr_t) &int_13
);
197 idt_setoffset(d
++, (uintptr_t) &int_14
);
198 idt_setoffset(d
++, (uintptr_t) &int_15
);
199 idt_setoffset(d
++, (uintptr_t) &int_16
);
200 idt_setoffset(d
++, (uintptr_t) &int_17
);
201 idt_setoffset(d
++, (uintptr_t) &int_18
);
202 idt_setoffset(d
++, (uintptr_t) &int_19
);
203 idt_setoffset(d
++, (uintptr_t) &int_20
);
204 idt_setoffset(d
++, (uintptr_t) &int_21
);
205 idt_setoffset(d
++, (uintptr_t) &int_22
);
206 idt_setoffset(d
++, (uintptr_t) &int_23
);
207 idt_setoffset(d
++, (uintptr_t) &int_24
);
208 idt_setoffset(d
++, (uintptr_t) &int_25
);
209 idt_setoffset(d
++, (uintptr_t) &int_26
);
210 idt_setoffset(d
++, (uintptr_t) &int_27
);
211 idt_setoffset(d
++, (uintptr_t) &int_28
);
212 idt_setoffset(d
++, (uintptr_t) &int_29
);
213 idt_setoffset(d
++, (uintptr_t) &int_30
);
214 idt_setoffset(d
++, (uintptr_t) &int_31
);
215 idt_setoffset(d
++, (uintptr_t) &int_32
);
216 idt_setoffset(d
++, (uintptr_t) &int_33
);
217 idt_setoffset(d
++, (uintptr_t) &int_34
);
218 idt_setoffset(d
++, (uintptr_t) &int_35
);
219 idt_setoffset(d
++, (uintptr_t) &int_36
);
220 idt_setoffset(d
++, (uintptr_t) &int_37
);
221 idt_setoffset(d
++, (uintptr_t) &int_38
);
222 idt_setoffset(d
++, (uintptr_t) &int_39
);
223 idt_setoffset(d
++, (uintptr_t) &int_40
);
224 idt_setoffset(d
++, (uintptr_t) &int_41
);
225 idt_setoffset(d
++, (uintptr_t) &int_42
);
226 idt_setoffset(d
++, (uintptr_t) &int_43
);
227 idt_setoffset(d
++, (uintptr_t) &int_44
);
228 idt_setoffset(d
++, (uintptr_t) &int_45
);
229 idt_setoffset(d
++, (uintptr_t) &int_46
);
230 idt_setoffset(d
++, (uintptr_t) &int_47
);
231 idt_setoffset(d
++, (uintptr_t) &int_48
);
232 idt_setoffset(d
++, (uintptr_t) &int_49
);
233 idt_setoffset(d
++, (uintptr_t) &int_50
);
234 idt_setoffset(d
++, (uintptr_t) &int_51
);
235 idt_setoffset(d
++, (uintptr_t) &int_52
);
236 idt_setoffset(d
++, (uintptr_t) &int_53
);
237 idt_setoffset(d
++, (uintptr_t) &int_54
);
238 idt_setoffset(d
++, (uintptr_t) &int_55
);
239 idt_setoffset(d
++, (uintptr_t) &int_56
);
240 idt_setoffset(d
++, (uintptr_t) &int_57
);
241 idt_setoffset(d
++, (uintptr_t) &int_58
);
242 idt_setoffset(d
++, (uintptr_t) &int_59
);
243 idt_setoffset(d
++, (uintptr_t) &int_60
);
244 idt_setoffset(d
++, (uintptr_t) &int_61
);
245 idt_setoffset(d
++, (uintptr_t) &int_62
);
246 idt_setoffset(d
++, (uintptr_t) &int_63
);
249 /** Initialize segmentation - code/data/idt tables
254 descriptor_t
*gdt_p
= (descriptor_t
*) gdtr
.base
;
255 tss_descriptor_t
*tss_desc
;
258 * Each CPU has its private GDT and TSS.
259 * All CPUs share one IDT.
262 if (config
.cpu_active
== 1) {
265 * NOTE: bootstrap CPU has statically allocated TSS, because
266 * the heap hasn't been initialized so far.
271 * We are going to use malloc, which may return
272 * non boot-mapped pointer, initialize the CR3 register
275 write_cr3((uintptr_t) AS_KERNEL
->genarch
.page_table
);
277 tss_p
= (tss_t
*) malloc(sizeof(tss_t
));
279 panic("Cannot allocate TSS.");
282 tss_initialize(tss_p
);
284 tss_desc
= (tss_descriptor_t
*) (&gdt_p
[TSS_DES
]);
285 tss_desc
->present
= 1;
286 tss_desc
->type
= AR_TSS
;
287 tss_desc
->dpl
= PL_KERNEL
;
289 gdt_tss_setbase(&gdt_p
[TSS_DES
], (uintptr_t) tss_p
);
290 gdt_tss_setlimit(&gdt_p
[TSS_DES
], TSS_BASIC_SIZE
- 1);
295 * As of this moment, the current CPU has its own GDT pointing
296 * to its own TSS. We just need to load the TR register.
298 tr_load(GDT_SELECTOR(TSS_DES
));