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