xref: /haiku/src/system/kernel/arch/x86/32/descriptors.cpp (revision 30afb18c8f2ac5d063924bc4e6239bf7c1c7d192)
1 /*
2  * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch.
3  * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de.
4  * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
5  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
6  * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
7  * Distributed under the terms of the MIT License.
8  *
9  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
10  * Distributed under the terms of the NewOS License.
11  */
12 
13 
14 #include <arch/x86/descriptors.h>
15 
16 #include <stdio.h>
17 
18 #include <boot/kernel_args.h>
19 #include <cpu.h>
20 #include <tls.h>
21 #include <vm/vm.h>
22 #include <vm/vm_priv.h>
23 
24 #include <arch/int.h>
25 #include <arch/user_debugger.h>
26 
27 #include "interrupts.h"
28 
29 
30 static interrupt_descriptor* sIDTs[B_MAX_CPU_COUNT];
31 
32 // table with functions handling respective interrupts
33 typedef void interrupt_handler_function(struct iframe* frame);
34 
35 static const uint32 kInterruptHandlerTableSize = 256;
36 interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize];
37 
38 segment_descriptor* gGDT;
39 
40 
41 /*!	Initializes a descriptor in an IDT.
42 */
43 static void
44 set_gate(interrupt_descriptor *gate_addr, addr_t addr, int type, int dpl)
45 {
46 	unsigned int gate1; // first byte of gate desc
47 	unsigned int gate2; // second byte of gate desc
48 
49 	gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr);
50 	gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8);
51 
52 	gate_addr->a = gate1;
53 	gate_addr->b = gate2;
54 }
55 
56 
57 /*!	Initializes the descriptor for interrupt vector \a n in the IDT of the
58 	specified CPU to an interrupt-gate descriptor with the given procedure
59 	address.
60 	For CPUs other than the boot CPU it must not be called before
61 	arch_int_init_post_vm().
62 */
63 static void
64 set_interrupt_gate(int32 cpu, int n, void (*addr)())
65 {
66 	set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL);
67 }
68 
69 
70 /*!	Initializes the descriptor for interrupt vector \a n in the IDT of the
71 	specified CPU to an trap-gate descriptor with the given procedure address.
72 	For CPUs other than the boot CPU it must not be called before
73 	arch_int_init_post_vm().
74 */
75 static void
76 set_trap_gate(int32 cpu, int n, void (*addr)())
77 {
78 	set_gate(&sIDTs[cpu][n], (unsigned int)addr, 15, DPL_USER);
79 }
80 
81 
82 /*!	Initializes the descriptor for interrupt vector \a n in the IDT of CPU
83 	\a cpu to a task-gate descripter referring to the TSS segment identified
84 	by TSS segment selector \a segment.
85 	For CPUs other than the boot CPU it must not be called before
86 	arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
87 */
88 static void
89 set_task_gate(int32 cpu, int32 n, int32 segment)
90 {
91 	sIDTs[cpu][n].a = (segment << 16);
92 	sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
93 }
94 
95 
96 static void
97 load_tss(int cpu)
98 {
99 	short seg = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL;
100 	asm("ltr %%ax" : : "a" (seg));
101 }
102 
103 
104 //	#pragma mark - Double fault handling
105 
106 
107 void
108 x86_double_fault_exception(struct iframe* frame)
109 {
110 	int cpu = x86_double_fault_get_cpu();
111 
112 	// The double fault iframe contains no useful information (as
113 	// per Intel's architecture spec). Thus we simply save the
114 	// information from the (unhandlable) exception which caused the
115 	// double in our iframe. This will result even in useful stack
116 	// traces. Only problem is that we trust that at least the
117 	// TSS is still accessible.
118 	struct tss *tss = &gCPU[cpu].arch.tss;
119 
120 	frame->cs = tss->cs;
121 	frame->es = tss->es;
122 	frame->ds = tss->ds;
123 	frame->fs = tss->fs;
124 	frame->gs = tss->gs;
125 	frame->ip = tss->eip;
126 	frame->bp = tss->ebp;
127 	frame->sp = tss->esp;
128 	frame->ax = tss->eax;
129 	frame->bx = tss->ebx;
130 	frame->cx = tss->ecx;
131 	frame->dx = tss->edx;
132 	frame->si = tss->esi;
133 	frame->di = tss->edi;
134 	frame->flags = tss->eflags;
135 
136 	// Use a special handler for page faults which avoids the triple fault
137 	// pitfalls.
138 	set_interrupt_gate(cpu, 14, &trap14_double_fault);
139 
140 	debug_double_fault(cpu);
141 }
142 
143 
144 void
145 x86_page_fault_exception_double_fault(struct iframe* frame)
146 {
147 	addr_t cr2 = x86_read_cr2();
148 
149 	// Only if this CPU has a fault handler, we're allowed to be here.
150 	cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()];
151 	addr_t faultHandler = cpu.fault_handler;
152 	if (faultHandler != 0) {
153 		debug_set_page_fault_info(cr2, frame->ip,
154 			(frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
155 		frame->ip = faultHandler;
156 		frame->bp = cpu.fault_handler_stack_pointer;
157 		return;
158 	}
159 
160 	// No fault handler. This is bad. Since we originally came from a double
161 	// fault, we don't try to reenter the kernel debugger. Instead we just
162 	// print the info we've got and enter an infinite loop.
163 	kprintf("Page fault in double fault debugger without fault handler! "
164 		"Touching address %p from eip %p. Entering infinite loop...\n",
165 		(void*)cr2, (void*)frame->ip);
166 
167 	while (true);
168 }
169 
170 
171 static void
172 init_double_fault(int cpuNum)
173 {
174 	// set up the double fault TSS
175 	struct tss* tss = &gCPU[cpuNum].arch.double_fault_tss;
176 
177 	memset(tss, 0, sizeof(struct tss));
178 	size_t stackSize;
179 	tss->sp0 = (addr_t)x86_get_double_fault_stack(cpuNum, &stackSize);
180 	tss->sp0 += stackSize;
181 	tss->ss0 = KERNEL_DATA_SEG;
182 	tss->cr3 = x86_read_cr3();
183 		// copy the current cr3 to the double fault cr3
184 	tss->eip = (uint32)&double_fault;
185 	tss->es = KERNEL_DATA_SEG;
186 	tss->cs = KERNEL_CODE_SEG;
187 	tss->ss = KERNEL_DATA_SEG;
188 	tss->esp = tss->sp0;
189 	tss->ds = KERNEL_DATA_SEG;
190 	tss->fs = KERNEL_DATA_SEG;
191 	tss->gs = KERNEL_DATA_SEG;
192 	tss->ldt_seg_selector = 0;
193 	tss->io_map_base = sizeof(struct tss);
194 
195 	// add TSS descriptor for this new TSS
196 	uint16 tssSegmentDescriptorIndex = DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum;
197 	set_tss_descriptor(&gGDT[tssSegmentDescriptorIndex],
198 		(addr_t)tss, sizeof(struct tss));
199 
200 	set_task_gate(cpuNum, 8, tssSegmentDescriptorIndex << 3);
201 }
202 
203 
204 //	#pragma mark -
205 
206 
207 void
208 x86_descriptors_init(kernel_args* args)
209 {
210 	uint32 i;
211 	interrupt_handler_function** table;
212 
213 	// Get the GDT and boot CPU IDT set up by the boot loader.
214 	gGDT = (segment_descriptor*)args->arch_args.vir_gdt;
215 	sIDTs[0] = (interrupt_descriptor *)(addr_t)args->arch_args.vir_idt;
216 
217 	set_interrupt_gate(0, 0, &trap0);
218 	set_interrupt_gate(0, 1, &trap1);
219 	set_interrupt_gate(0, 2, &trap2);
220 	set_trap_gate(0, 3, &trap3);
221 	set_interrupt_gate(0, 4, &trap4);
222 	set_interrupt_gate(0, 5, &trap5);
223 	set_interrupt_gate(0, 6, &trap6);
224 	set_interrupt_gate(0, 7, &trap7);
225 	// trap8 (double fault) is set in init_double_fault().
226 	set_interrupt_gate(0, 9, &trap9);
227 	set_interrupt_gate(0, 10, &trap10);
228 	set_interrupt_gate(0, 11, &trap11);
229 	set_interrupt_gate(0, 12, &trap12);
230 	set_interrupt_gate(0, 13, &trap13);
231 	set_interrupt_gate(0, 14, &trap14);
232 //	set_interrupt_gate(0, 15, &trap15);
233 	set_interrupt_gate(0, 16, &trap16);
234 	set_interrupt_gate(0, 17, &trap17);
235 	set_interrupt_gate(0, 18, &trap18);
236 	set_interrupt_gate(0, 19, &trap19);
237 
238 	// legacy or ioapic interrupts
239 	set_interrupt_gate(0, 32, &trap32);
240 	set_interrupt_gate(0, 33, &trap33);
241 	set_interrupt_gate(0, 34, &trap34);
242 	set_interrupt_gate(0, 35, &trap35);
243 	set_interrupt_gate(0, 36, &trap36);
244 	set_interrupt_gate(0, 37, &trap37);
245 	set_interrupt_gate(0, 38, &trap38);
246 	set_interrupt_gate(0, 39, &trap39);
247 	set_interrupt_gate(0, 40, &trap40);
248 	set_interrupt_gate(0, 41, &trap41);
249 	set_interrupt_gate(0, 42, &trap42);
250 	set_interrupt_gate(0, 43, &trap43);
251 	set_interrupt_gate(0, 44, &trap44);
252 	set_interrupt_gate(0, 45, &trap45);
253 	set_interrupt_gate(0, 46, &trap46);
254 	set_interrupt_gate(0, 47, &trap47);
255 
256 	// additional ioapic interrupts
257 	set_interrupt_gate(0, 48, &trap48);
258 	set_interrupt_gate(0, 49, &trap49);
259 	set_interrupt_gate(0, 50, &trap50);
260 	set_interrupt_gate(0, 51, &trap51);
261 	set_interrupt_gate(0, 52, &trap52);
262 	set_interrupt_gate(0, 53, &trap53);
263 	set_interrupt_gate(0, 54, &trap54);
264 	set_interrupt_gate(0, 55, &trap55);
265 
266 	// configurable msi or msi-x interrupts
267 	set_interrupt_gate(0, 56, &trap56);
268 	set_interrupt_gate(0, 57, &trap57);
269 	set_interrupt_gate(0, 58, &trap58);
270 	set_interrupt_gate(0, 59, &trap59);
271 	set_interrupt_gate(0, 60, &trap60);
272 	set_interrupt_gate(0, 61, &trap61);
273 	set_interrupt_gate(0, 62, &trap62);
274 	set_interrupt_gate(0, 63, &trap63);
275 	set_interrupt_gate(0, 64, &trap64);
276 	set_interrupt_gate(0, 65, &trap65);
277 	set_interrupt_gate(0, 66, &trap66);
278 	set_interrupt_gate(0, 67, &trap67);
279 	set_interrupt_gate(0, 68, &trap68);
280 	set_interrupt_gate(0, 69, &trap69);
281 	set_interrupt_gate(0, 70, &trap70);
282 	set_interrupt_gate(0, 71, &trap71);
283 	set_interrupt_gate(0, 72, &trap72);
284 	set_interrupt_gate(0, 73, &trap73);
285 	set_interrupt_gate(0, 74, &trap74);
286 	set_interrupt_gate(0, 75, &trap75);
287 	set_interrupt_gate(0, 76, &trap76);
288 	set_interrupt_gate(0, 77, &trap77);
289 	set_interrupt_gate(0, 78, &trap78);
290 	set_interrupt_gate(0, 79, &trap79);
291 	set_interrupt_gate(0, 80, &trap80);
292 	set_interrupt_gate(0, 81, &trap81);
293 	set_interrupt_gate(0, 82, &trap82);
294 	set_interrupt_gate(0, 83, &trap83);
295 	set_interrupt_gate(0, 84, &trap84);
296 	set_interrupt_gate(0, 85, &trap85);
297 	set_interrupt_gate(0, 86, &trap86);
298 	set_interrupt_gate(0, 87, &trap87);
299 	set_interrupt_gate(0, 88, &trap88);
300 	set_interrupt_gate(0, 89, &trap89);
301 	set_interrupt_gate(0, 90, &trap90);
302 	set_interrupt_gate(0, 91, &trap91);
303 	set_interrupt_gate(0, 92, &trap92);
304 	set_interrupt_gate(0, 93, &trap93);
305 	set_interrupt_gate(0, 94, &trap94);
306 	set_interrupt_gate(0, 95, &trap95);
307 	set_interrupt_gate(0, 96, &trap96);
308 	set_interrupt_gate(0, 97, &trap97);
309 
310 	set_trap_gate(0, 98, &trap98);	// for performance testing only
311 	set_trap_gate(0, 99, &trap99);	// syscall interrupt
312 
313 	reserve_io_interrupt_vectors(2, 98);
314 
315 	// configurable msi or msi-x interrupts
316 	set_interrupt_gate(0, 100, &trap100);
317 	set_interrupt_gate(0, 101, &trap101);
318 	set_interrupt_gate(0, 102, &trap102);
319 	set_interrupt_gate(0, 103, &trap103);
320 	set_interrupt_gate(0, 104, &trap104);
321 	set_interrupt_gate(0, 105, &trap105);
322 	set_interrupt_gate(0, 106, &trap106);
323 	set_interrupt_gate(0, 107, &trap107);
324 	set_interrupt_gate(0, 108, &trap108);
325 	set_interrupt_gate(0, 109, &trap109);
326 	set_interrupt_gate(0, 110, &trap110);
327 	set_interrupt_gate(0, 111, &trap111);
328 	set_interrupt_gate(0, 112, &trap112);
329 	set_interrupt_gate(0, 113, &trap113);
330 	set_interrupt_gate(0, 114, &trap114);
331 	set_interrupt_gate(0, 115, &trap115);
332 	set_interrupt_gate(0, 116, &trap116);
333 	set_interrupt_gate(0, 117, &trap117);
334 	set_interrupt_gate(0, 118, &trap118);
335 	set_interrupt_gate(0, 119, &trap119);
336 	set_interrupt_gate(0, 120, &trap120);
337 	set_interrupt_gate(0, 121, &trap121);
338 	set_interrupt_gate(0, 122, &trap122);
339 	set_interrupt_gate(0, 123, &trap123);
340 	set_interrupt_gate(0, 124, &trap124);
341 	set_interrupt_gate(0, 125, &trap125);
342 	set_interrupt_gate(0, 126, &trap126);
343 	set_interrupt_gate(0, 127, &trap127);
344 	set_interrupt_gate(0, 128, &trap128);
345 	set_interrupt_gate(0, 129, &trap129);
346 	set_interrupt_gate(0, 130, &trap130);
347 	set_interrupt_gate(0, 131, &trap131);
348 	set_interrupt_gate(0, 132, &trap132);
349 	set_interrupt_gate(0, 133, &trap133);
350 	set_interrupt_gate(0, 134, &trap134);
351 	set_interrupt_gate(0, 135, &trap135);
352 	set_interrupt_gate(0, 136, &trap136);
353 	set_interrupt_gate(0, 137, &trap137);
354 	set_interrupt_gate(0, 138, &trap138);
355 	set_interrupt_gate(0, 139, &trap139);
356 	set_interrupt_gate(0, 140, &trap140);
357 	set_interrupt_gate(0, 141, &trap141);
358 	set_interrupt_gate(0, 142, &trap142);
359 	set_interrupt_gate(0, 143, &trap143);
360 	set_interrupt_gate(0, 144, &trap144);
361 	set_interrupt_gate(0, 145, &trap145);
362 	set_interrupt_gate(0, 146, &trap146);
363 	set_interrupt_gate(0, 147, &trap147);
364 	set_interrupt_gate(0, 148, &trap148);
365 	set_interrupt_gate(0, 149, &trap149);
366 	set_interrupt_gate(0, 150, &trap150);
367 	set_interrupt_gate(0, 151, &trap151);
368 	set_interrupt_gate(0, 152, &trap152);
369 	set_interrupt_gate(0, 153, &trap153);
370 	set_interrupt_gate(0, 154, &trap154);
371 	set_interrupt_gate(0, 155, &trap155);
372 	set_interrupt_gate(0, 156, &trap156);
373 	set_interrupt_gate(0, 157, &trap157);
374 	set_interrupt_gate(0, 158, &trap158);
375 	set_interrupt_gate(0, 159, &trap159);
376 	set_interrupt_gate(0, 160, &trap160);
377 	set_interrupt_gate(0, 161, &trap161);
378 	set_interrupt_gate(0, 162, &trap162);
379 	set_interrupt_gate(0, 163, &trap163);
380 	set_interrupt_gate(0, 164, &trap164);
381 	set_interrupt_gate(0, 165, &trap165);
382 	set_interrupt_gate(0, 166, &trap166);
383 	set_interrupt_gate(0, 167, &trap167);
384 	set_interrupt_gate(0, 168, &trap168);
385 	set_interrupt_gate(0, 169, &trap169);
386 	set_interrupt_gate(0, 170, &trap170);
387 	set_interrupt_gate(0, 171, &trap171);
388 	set_interrupt_gate(0, 172, &trap172);
389 	set_interrupt_gate(0, 173, &trap173);
390 	set_interrupt_gate(0, 174, &trap174);
391 	set_interrupt_gate(0, 175, &trap175);
392 	set_interrupt_gate(0, 176, &trap176);
393 	set_interrupt_gate(0, 177, &trap177);
394 	set_interrupt_gate(0, 178, &trap178);
395 	set_interrupt_gate(0, 179, &trap179);
396 	set_interrupt_gate(0, 180, &trap180);
397 	set_interrupt_gate(0, 181, &trap181);
398 	set_interrupt_gate(0, 182, &trap182);
399 	set_interrupt_gate(0, 183, &trap183);
400 	set_interrupt_gate(0, 184, &trap184);
401 	set_interrupt_gate(0, 185, &trap185);
402 	set_interrupt_gate(0, 186, &trap186);
403 	set_interrupt_gate(0, 187, &trap187);
404 	set_interrupt_gate(0, 188, &trap188);
405 	set_interrupt_gate(0, 189, &trap189);
406 	set_interrupt_gate(0, 190, &trap190);
407 	set_interrupt_gate(0, 191, &trap191);
408 	set_interrupt_gate(0, 192, &trap192);
409 	set_interrupt_gate(0, 193, &trap193);
410 	set_interrupt_gate(0, 194, &trap194);
411 	set_interrupt_gate(0, 195, &trap195);
412 	set_interrupt_gate(0, 196, &trap196);
413 	set_interrupt_gate(0, 197, &trap197);
414 	set_interrupt_gate(0, 198, &trap198);
415 	set_interrupt_gate(0, 199, &trap199);
416 	set_interrupt_gate(0, 200, &trap200);
417 	set_interrupt_gate(0, 201, &trap201);
418 	set_interrupt_gate(0, 202, &trap202);
419 	set_interrupt_gate(0, 203, &trap203);
420 	set_interrupt_gate(0, 204, &trap204);
421 	set_interrupt_gate(0, 205, &trap205);
422 	set_interrupt_gate(0, 206, &trap206);
423 	set_interrupt_gate(0, 207, &trap207);
424 	set_interrupt_gate(0, 208, &trap208);
425 	set_interrupt_gate(0, 209, &trap209);
426 	set_interrupt_gate(0, 210, &trap210);
427 	set_interrupt_gate(0, 211, &trap211);
428 	set_interrupt_gate(0, 212, &trap212);
429 	set_interrupt_gate(0, 213, &trap213);
430 	set_interrupt_gate(0, 214, &trap214);
431 	set_interrupt_gate(0, 215, &trap215);
432 	set_interrupt_gate(0, 216, &trap216);
433 	set_interrupt_gate(0, 217, &trap217);
434 	set_interrupt_gate(0, 218, &trap218);
435 	set_interrupt_gate(0, 219, &trap219);
436 	set_interrupt_gate(0, 220, &trap220);
437 	set_interrupt_gate(0, 221, &trap221);
438 	set_interrupt_gate(0, 222, &trap222);
439 	set_interrupt_gate(0, 223, &trap223);
440 	set_interrupt_gate(0, 224, &trap224);
441 	set_interrupt_gate(0, 225, &trap225);
442 	set_interrupt_gate(0, 226, &trap226);
443 	set_interrupt_gate(0, 227, &trap227);
444 	set_interrupt_gate(0, 228, &trap228);
445 	set_interrupt_gate(0, 229, &trap229);
446 	set_interrupt_gate(0, 230, &trap230);
447 	set_interrupt_gate(0, 231, &trap231);
448 	set_interrupt_gate(0, 232, &trap232);
449 	set_interrupt_gate(0, 233, &trap233);
450 	set_interrupt_gate(0, 234, &trap234);
451 	set_interrupt_gate(0, 235, &trap235);
452 	set_interrupt_gate(0, 236, &trap236);
453 	set_interrupt_gate(0, 237, &trap237);
454 	set_interrupt_gate(0, 238, &trap238);
455 	set_interrupt_gate(0, 239, &trap239);
456 	set_interrupt_gate(0, 240, &trap240);
457 	set_interrupt_gate(0, 241, &trap241);
458 	set_interrupt_gate(0, 242, &trap242);
459 	set_interrupt_gate(0, 243, &trap243);
460 	set_interrupt_gate(0, 244, &trap244);
461 	set_interrupt_gate(0, 245, &trap245);
462 	set_interrupt_gate(0, 246, &trap246);
463 	set_interrupt_gate(0, 247, &trap247);
464 	set_interrupt_gate(0, 248, &trap248);
465 	set_interrupt_gate(0, 249, &trap249);
466 	set_interrupt_gate(0, 250, &trap250);
467 
468 	// smp / apic local interrupts
469 	set_interrupt_gate(0, 251, &trap251);
470 	set_interrupt_gate(0, 252, &trap252);
471 	set_interrupt_gate(0, 253, &trap253);
472 	set_interrupt_gate(0, 254, &trap254);
473 	set_interrupt_gate(0, 255, &trap255);
474 
475 	// init interrupt handler table
476 	table = gInterruptHandlerTable;
477 
478 	// defaults
479 	for (i = 0; i < ARCH_INTERRUPT_BASE; i++)
480 		table[i] = x86_invalid_exception;
481 	for (i = ARCH_INTERRUPT_BASE; i < kInterruptHandlerTableSize; i++)
482 		table[i] = x86_hardware_interrupt;
483 
484 	table[0] = x86_unexpected_exception;	// Divide Error Exception (#DE)
485 	table[1] = x86_handle_debug_exception;	// Debug Exception (#DB)
486 	table[2] = x86_fatal_exception;			// NMI Interrupt
487 	table[3] = x86_handle_breakpoint_exception; // Breakpoint Exception (#BP)
488 	table[4] = x86_unexpected_exception;	// Overflow Exception (#OF)
489 	table[5] = x86_unexpected_exception;	// BOUND Range Exceeded Exception (#BR)
490 	table[6] = x86_unexpected_exception;	// Invalid Opcode Exception (#UD)
491 	table[7] = x86_fatal_exception;			// Device Not Available Exception (#NM)
492 	table[8] = x86_double_fault_exception;	// Double Fault Exception (#DF)
493 	table[9] = x86_fatal_exception;			// Coprocessor Segment Overrun
494 	table[10] = x86_fatal_exception;		// Invalid TSS Exception (#TS)
495 	table[11] = x86_fatal_exception;		// Segment Not Present (#NP)
496 	table[12] = x86_fatal_exception;		// Stack Fault Exception (#SS)
497 	table[13] = x86_unexpected_exception;	// General Protection Exception (#GP)
498 	table[14] = x86_page_fault_exception;	// Page-Fault Exception (#PF)
499 	table[16] = x86_unexpected_exception;	// x87 FPU Floating-Point Error (#MF)
500 	table[17] = x86_unexpected_exception;	// Alignment Check Exception (#AC)
501 	table[18] = x86_fatal_exception;		// Machine-Check Exception (#MC)
502 	table[19] = x86_unexpected_exception;	// SIMD Floating-Point Exception (#XF)
503 }
504 
505 
506 void
507 x86_descriptors_init_percpu(kernel_args* args, int cpu)
508 {
509 	// load the TSS for this cpu
510 	// note the main cpu gets initialized in x86_descriptors_init_post_vm()
511 	if (cpu != 0) {
512 		load_tss(cpu);
513 
514 		// set the IDT
515 		struct {
516 			uint16	limit;
517 			void*	address;
518 		} _PACKED descriptor = {
519 			256 * 8 - 1,	// 256 descriptors, 8 bytes each (-1 for "limit")
520 			sIDTs[cpu]
521 		};
522 
523 		asm volatile("lidt	%0" : : "m"(descriptor));
524 	}
525 }
526 
527 
528 status_t
529 x86_descriptors_init_post_vm(kernel_args* args)
530 {
531 	uint32 i;
532 
533 	// account for the segment descriptors
534 	create_area("gdt", (void **)&gGDT, B_EXACT_ADDRESS, B_PAGE_SIZE,
535 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
536 
537 	// create IDT area for the boot CPU
538 	area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
539 		B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
540 	if (area < B_OK)
541 		return area;
542 
543 	// create IDTs for the off-boot CPU
544 	size_t idtSize = 256 * 8;
545 		// 256 8 bytes-sized descriptors
546 	if (args->num_cpus > 0) {
547 		size_t areaSize = ROUNDUP(args->num_cpus * idtSize, B_PAGE_SIZE);
548 		interrupt_descriptor* idt;
549 		virtual_address_restrictions virtualRestrictions = {};
550 		virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
551 		physical_address_restrictions physicalRestrictions = {};
552 		area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS,
553 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
554 			&virtualRestrictions, &physicalRestrictions, (void**)&idt);
555 		if (area < 0)
556 			return area;
557 
558 		for (i = 1; i < args->num_cpus; i++) {
559 			sIDTs[i] = idt;
560 			memcpy(idt, sIDTs[0], idtSize);
561 			idt += 256;
562 			// The CPU's IDTR will be set in arch_cpu_init_percpu().
563 		}
564 	}
565 
566 	// setup task-state segments
567 	for (i = 0; i < args->num_cpus; i++) {
568 		// initialize the regular and double fault tss stored in the per-cpu
569 		// structure
570 		memset(&gCPU[i].arch.tss, 0, sizeof(struct tss));
571 		gCPU[i].arch.tss.ss0 = KERNEL_DATA_SEG;
572 		gCPU[i].arch.tss.io_map_base = sizeof(struct tss);
573 
574 		// add TSS descriptor for this new TSS
575 		set_tss_descriptor(&gGDT[TSS_SEGMENT(i)], (addr_t)&gCPU[i].arch.tss,
576 			sizeof(struct tss));
577 
578 		// initialize the double fault tss
579 		init_double_fault(i);
580 	}
581 
582 	// set the current hardware task on cpu 0
583 	load_tss(0);
584 
585 	// setup TLS descriptors (one for every CPU)
586 
587 	for (i = 0; i < args->num_cpus; i++) {
588 		set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE,
589 			DT_DATA_WRITEABLE, DPL_USER);
590 	}
591 
592 	return B_OK;
593 }
594